opencv:基于凹点匹配的重叠分割
有重叠部分的两个同类型物体由于灰度近似,所以一般较难分类(如下图)。实际操作中是使用一种凹点匹配的方法来寻找分割点进行分割。
两个重叠物体 其中黄色十字地方就是凹点
寻找到凹点是解决该分割问题的关键。这里采用如下方法:
1、寻找该图像的最小凸闭包,
2、图闭包和凹图形相减得到凹区域
3、提取凹区域的轮廓
4、按照区域面积大小最为权重,选取最大的两个区域作为凹点所在区域
5、遍历这两个区域,寻找距离最短的两个点作为凹点
6、基于该两个凹点分割
关键实现:
- /**
- * @brief searchConcaveRegion 寻找凹区域
- * @param hull 凸包点集
- * @param src 原图像(二值图)
- * @return 返回 图像凹区域
- */
- Mat searchConcaveRegion(std::vector<std::vector<Point> >hull, Mat &src)
- {
- if(src.empty())
- return Mat();
- Mat concaveRegion=Mat::zeros(src.rows,src.cols,CV_8UC1);
- //填充凸包点集
- for(int i=0;i<hull.size();++i)
- drawContours(concaveRegion,hull,i,Scalar(255),CV_FILLED);
- concaveRegion=concaveRegion-src*255;
- medianBlur(concaveRegion,concaveRegion,3);
- return concaveRegion;
- }
- /**
- * @brief searchConcavePoint
- * @param src 凹区域图像
- * @return 返回匹配好的凹点对(2个)
- */
- std::vector<Point2f> searchConcavePoint(Mat &src)
- {
- std::vector<Point2f> ConcavePoint;
- //轮廓寻找
- std::vector<std::vector<Point> > contour;//用来存储轮廓
- std::vector<Vec4i> hierarchys;
- findContours(src, contour, hierarchys,
- CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE, Point(0, 0)); //寻找轮廓
- //凹区域少于2要退出
- if(contour.size()<2)
- return ConcavePoint;
- //按照轮廓面积大小排序
- std::sort(contour.begin(),contour.end(),[](const std::vector<Point> &s1,
- const std::vector<Point> &s2){
- double a1=contourArea(s1);
- double a2=contourArea(s2);
- return a1>a2;
- });
- int minDistance=100000000;//最短距离
- for(int i=0;i<contour[0].size();++i)
- for(int j=0;j<contour[1].size();++j)
- {
- //欧氏距离
- int d= std::sqrt(std::pow((contour[0][i].x-contour[1][j].x),2)+
- std::pow((contour[0][i].y-contour[1][j].y),2));
- if(minDistance>d)
- {
- minDistance=d;
- ConcavePoint.push_back(contour[0][i]);
- ConcavePoint.push_back(contour[1][j]);
- }
- }
- qDebug()<<"ConcavePoint0:"<<ConcavePoint[0].x<<","<<ConcavePoint[0].y;
- qDebug()<<"ConcavePoint1:"<<ConcavePoint[1].x<<","<<ConcavePoint[1].y;
- return ConcavePoint;
- }
注意:本文讨论的就是只有单一重叠区域的简单情况,对于一些多重叠区域,其凹点能否正确匹配是实现分割的关键。
效果:本人用这种方法来提取图像区域较为准确质心,防止质心偏移:
原始图 凹区域
分割结果 提取质心结果