分割识别图中的纸盒区域
1.使用双边变换进行滤波操作,保留并增强边缘信息
2.使用canny算子检测边缘信息,使用开运算去除小噪点
使用多边形逼近,画出边缘轮廓,对轮廓进行筛选操作
使用矩形直角、平行等特征构建向量模型筛选轮廓,使用直线连接矩形的四个角点位置,画出矩形位置
注:识别效果一般;采用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);
}
}