C++和opencv实现图像分割(二)

一、目标图片:

C++和opencv实现图像分割(二)_第1张图片

二、分割目的:

分割识别图中的纸盒区域

三、实现思路及步骤:

C++和opencv实现图像分割(二)_第2张图片

1.使用双边变换进行滤波操作,保留并增强边缘信息

2.使用canny算子检测边缘信息,使用开运算去除小噪点

 

C++和opencv实现图像分割(二)_第3张图片

使用多边形逼近,画出边缘轮廓,对轮廓进行筛选操作

 

C++和opencv实现图像分割(二)_第4张图片

使用矩形直角、平行等特征构建向量模型筛选轮廓,使用直线连接矩形的四个角点位置,画出矩形位置

注:识别效果一般;采用mask-rcnn机器学习方法重新进行纸箱模型分割,效果有着显著提升,可以进我的个人主页查看,博客连接网址:https://blog.csdn.net/weixin_38341864/article/details/88819668

四、完整代码实例:

#include 
#include 
#include 
#include 

using namespace std;
using namespace cv;

#define PI 3.1415

int thresh = 280, N = 1;       //轮廓提取参数调节
float EpsilonThd = 0.05;
float MaxRegion = 200000, MinRegion = 8000;
float SharpeThd = 2.5;
float AngleMaxThd = 105;
float AngleMinThd = 75;
float AngleParaThd = 10;
float EqualThd = 10;       //两点是否为同一点的距离阈值

void findSquares(const Mat& image, vector>& squares);
double AngleCal(Point pt1, Point pt2, Point pt0);
void RemoveInvalid(vector> &corner);      //移除无效轮廓
bool CompareCorner(vector corner1, vector corner2);     //判断角点是否为同一个点
void drawSquares(Mat& image, const vector >& squares);

float getDistance(Point2f a, Point2f b)
{
	return sqrt(pow(a.x - b.x, 2) + pow(a.y - b.y, 2));
}

int main()
{
	Mat image = imread("D:\\photoclub\\2\\5_1.jpg");
	if (!image.data)
	{
		cout << "打开图片有误" << endl;
		return -1;
	}

	Mat image_gray;
	vector> squares;

	cvtColor(image, image_gray, COLOR_BGR2GRAY);

	imshow("SorceImage", image_gray);

	findSquares(image_gray, squares);
	RemoveInvalid(squares);
	drawSquares(image, squares);

	imshow("Result", image);

	waitKey();

	return 0;
}

// helper function:
// finds a cosine of angle between vectors
// from pt0->pt1 and from pt0->pt2
double AngleCal(Point pt1, Point pt2, Point pt0)
{
	double dx1 = pt1.x - pt0.x;
	double dy1 = pt1.y - pt0.y;
	double dx2 = pt2.x - pt0.x;
	double dy2 = pt2.y - pt0.y;
	return (dx1*dx2 + dy1 * dy2) / sqrt((dx1*dx1 + dy1 * dy1)*(dx2*dx2 + dy2 * dy2) + 1e-10);
}


void findSquares(const Mat& image, vector>& squares)
{
	/*找到长方形的函数
	image 输入待查找长方形的图片
	squares 输出长方形点集*/

	int index = 0;
	RNG rng = theRNG();

	squares.clear();

	vector > contours;
	for (int con = 0; con < 1; con++)
	{
		Mat timg, cimg;
		image.convertTo(cimg, CV_8U, 0.5 + 0.5*con, 0);//cimg改变
		imshow("Image" + to_string(con), cimg);
		for (int th = 0; th < 3; th++)
		{
			bilateralFilter(cimg, timg, -1, 3 + th * 3, 15);//双边
			Mat gray;
			
			for (int l = 0; l < N; l++)
			{
				if (l == 0)
				{
					Canny(timg, gray, 5, thresh, 5);//canny
					imshow("canny" + to_string(th),gray);
					Mat kernel = getStructuringElement(MORPH_RECT, Size(5, 5));
					dilate(gray, gray, kernel, Point(-1, -1));//膨胀
				}
				else
				{
					gray = timg >= (l + 1) * 255 / N;//***GRAY->timg
				}
				int kernel_length = timg.cols;//invalid

				findContours(gray, contours, RETR_LIST, CHAIN_APPROX_NONE);//找轮廓

				Mat display;
				cvtColor(timg, display, COLOR_GRAY2BGR);

				vector approx;

				for (size_t i = 0; i < contours.size(); i++)
				{
					approxPolyDP(Mat(contours[i]), approx, arcLength(Mat(contours[i]), true)*EpsilonThd, true);      //多边形拟合

					Scalar color = { (double)rng(256),(double)rng(256) ,(double)rng(256) };//随机颜色
					drawContours(display, contours, i, color, 1);

					RotatedRect rect = minAreaRect(contours[i]);        //矩形特征
					double sharpe = rect.size.width / rect.size.height; //矩形长比高

					if (approx.size() == 4 &&//容器大小
						fabs(contourArea(Mat(approx))) > MinRegion &&//面积范围
						fabs(contourArea(Mat(approx))) < MaxRegion &&//面积范围
						sharpe < SharpeThd && //长宽比范围
						sharpe > 1.0 / SharpeThd &&//长宽比范围
						isContourConvex(Mat(approx)))
					{
						float maxAngle = 90, minAngle = 90;
						float rect_angle[3];

						for (int j = 2; j < 5; j++)
						{
							float angle = acos(AngleCal(approx[j % 4], approx[j - 2], approx[j - 1])) * 180 / PI;
							rect_angle[j - 2] = angle;

							maxAngle = MAX(maxAngle, angle);
							minAngle = MIN(minAngle, angle);
						}

						float paral = (abs(180 - rect_angle[1] - rect_angle[0]) + abs(180 - rect_angle[1] - rect_angle[2])) / 2;

						if (maxAngle < AngleMaxThd && minAngle > AngleMinThd && paral < AngleParaThd)
							squares.push_back(approx);
					}

				}
				imshow("轮廓"+to_string(index), display);
				index++;
			}
		}
	}

}

void RemoveInvalid(vector> &corner)
{
	if (corner.size() == 0)
		return;

	for (int i = 1; i < corner.size(); i++)
	{
		vector temp = corner[i];

		for (int j = 0; j < i; j++)
		{
			vector temp2 = corner[j];

			if (CompareCorner(temp, temp2))
			{
				corner.erase(corner.begin() + i);

				i--;
				break;
			}
		}
	}
}

bool CompareCorner(vector corner1, vector corner2)
{
	bool is_equal = false;

	for (int i = 0; i < corner1.size(); i++)
	{
		Point temp = corner1[i];

		for (int j = 0; j < corner2.size(); j++)
		{
			Point temp2 = corner2[j];

			if (getDistance((Point2f)temp, (Point2f)temp2) < EqualThd)
			{
				is_equal = true;
				break;
			}

		}

		if (!is_equal)
			break;
	}

	return is_equal;
}

void drawSquares(Mat& image, const vector >& squares)
{
	/*在已经找到长方形的图片上画出长方形
	image 待圈出长方形的图片
	squares 找到的长方形点集*/

	for (size_t i = 0; i < squares.size(); i++)
	{
		const Point* p = &squares[i][0];

		int n = (int)squares[i].size();
		if (p->x > 3 && p->y > 3)
			polylines(image, &p, &n, 1, true, Scalar(0, 255, 0), 2, LINE_AA);
	}
}




 

你可能感兴趣的:(opencv)