持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第30天,点击查看活动详情
在处理的结果方面,总感觉使用c++的处理效果要略微好于使用python的处理效果,不知道是不是我的错觉。最近对python实现的内容,我又通过QT进行了实现,主要就是对检测到的轮廓进行标记,绘制最小外接矩形。
算法的代码如下:
// 轮廓中绘制最小矩形
// 这里的图像我是使用的前面图像增强后的
void Widget::process_draw_minrectangle(Mat img, String image_save_path, float font_size, int font_thickness, int line_thickness)
{
Mat gray;
Mat dstImg = img.clone();
cvtColor(img, gray, COLOR_BGR2GRAY);
Mat binary;
// 自适应阈值分割
adaptiveThreshold(gray, binary, 127, ADAPTIVE_THRESH_GAUSSIAN_C, THRESH_BINARY, 11, -30);
imwrite("binary.jpg", binary);
Mat erode_img;
// 腐蚀
erode(binary, erode_img, 5);
imwrite("erode.jpg", erode_img);
// 建立结构保存寻找轮廓得到的数据点
std::vector<std::vector<Point> > contours;
std::vector<Vec4i> hierarchy;
findContours(binary, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
int count = 0;
vector<Rect> boundRect(contours.size());
vector<RotatedRect> box(contours.size());
Point2f rect[4];
// 对每一个轮廓进行遍历
for(int i=0;i<contours.size();i++)
{
box[i] = minAreaRect(Mat(contours[i]));
boundRect[i] = boundingRect((Mat(contours[i])));
circle(dstImg, Point(box[i].center.x, box[i].center.y), 5, Scalar(0, 255, 0), -1, 8);
box[i].points(rect); //把最小外接矩形四个端点复制给rect数组
//rectangle(dstImg, Point(boundRect[i].x, boundRect[i].y), Point(boundRect[i].x + boundRect[i].width, boundRect[i].y + boundRect[i].height), Scalar(0, 255, 0), 2, 8);
for(int j=0; j<4; j++)
{
// 绘制最小外接矩形的边
line(dstImg, rect[j], rect[(j+1)%4], Scalar(0, 0, 255), 2, 8);
}
}
imshow("dst", dstImg);
waitKey(0);
}
上述算法主要作用就是通过对最小轮廓的查找,记录轮廓的坐标点,然后利用绘制每条线段的方式找到最小外接矩形,算法的效率比较高,检测的事件在毫秒级。
下面是对一些实验结果的分析
上面是对轮廓的检测和绘制结果,在绘制矩形时同时计算出了其几何中心,也一并绘制出,所以看到的图像中存在一些绿色的圆点,即为整个矩形的中心点。
在上述代码中只需要注释掉circle一行即可不绘制图像的几何中心点,如下面所示。
同时,还可以在绘制时计算一下轮廓面积,去除较小可以忽略的轮廓,同时可以使用NMS的思想去除掉被大框圈住的小框等。