轮廓(图形)之凹点切分

原博客为:凹点切分,但是原博客算法存在诸多问题,因此这里修改了一下。

在常见的细胞计数,种子计数,总之总会遇到物体重叠的情况,有重叠部分的物体颜色近似,这样会把多个物体计数成一个,

寻找到凹点是解决该分割问题的关键。这里采用如下方法:

       1、寻找该图像的最小凸闭包,

       2、凸闭包和凹图形相减得到凹区域

       3、提取凹区域的轮廓

       4、按照区域面积大小最为权重,选取最大的两个区域作为凹点所在区域

       5、遍历这两个区域,寻找距离最短的两个点作为凹点

       6、基于该两个凹点分割
算法所达到的效果:

 

 代码展示:

#include <opencv2/opencv.hpp>
#include <iostream>
 
using namespace std;
using namespace cv;
 
Mat searchConcaveRegion(std::vector<std::vector<Point> >hull, Mat &src)  ;
std::vector<Point2f> searchConcavePoint(Mat &src) ;
 
void main()
{
    Mat img = imread("2.jpg", 1);
    Mat gray, gray_back;
 
    cvtColor(img, gray, CV_BGR2GRAY);
    threshold(gray, gray, 0, 255, CV_THRESH_OTSU);
    gray_back = gray.clone();
 
    //提取轮廓
    vector<vector<Point>>contours;
    findContours(gray, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
    drawContours(img, contours, -1, Scalar(0,0,255), 2);
 
    Mat aotu = searchConcaveRegion(contours, gray_back);
    vector<Point2f> pt;
    pt = searchConcavePoint(aotu);
 
    line(img, pt[pt.size() - 2], pt[pt.size() - 1], Scalar(255,0,0), 2, 8, 0);
 
    imshow("切割线", img);
    waitKey(0);
}
 
/** 
 * @brief searchConcaveRegion 寻找凹区域 
 * @param hull  凸包点集 
 * @param src  原图像(二值图) 
 * @return 返回 图像凹区域 
 */  
Mat searchConcaveRegion(std::vector<std::vector<Point> >contours, Mat &src)  
{  
    if(src.empty())  
        return Mat();  
 
    //遍历每个轮廓,寻找其凸包
    vector<vector<Point>>hull(contours.size());
    for(unsigned int i=0;i<contours.size();++i)
    {
        convexHull(Mat(contours[i]), hull[i],false);
    }
  
    //绘制轮廓及其凸包
    Mat drawing = Mat::zeros(src.size(), CV_8UC1);
    for(unsigned int i=0; i < contours.size(); ++i)
    {
        drawContours(drawing, hull, i, Scalar(255), -1, 8,vector<Vec4i>(), 0, Point());
        drawContours(drawing, contours, i, Scalar(0), -1, 8,vector<Vec4i>(), 0, Point());      
    }
 
    medianBlur(drawing, drawing, 3);
 
    imshow("凹区域", drawing);
 
    return drawing;
}  
  
/** 
 * @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]);  
            }  
        }  
    cout<<"ConcavePoint0:"<<ConcavePoint[ConcavePoint.size() - 2].x<<","<<ConcavePoint[ConcavePoint.size() - 2].y<<endl;  
    cout<<"ConcavePoint1:"<<ConcavePoint[ConcavePoint.size() - 1].x<<","<<ConcavePoint[ConcavePoint.size() - 1].y<<endl;  
  
    return ConcavePoint;  
}  

下面是原作者通过距离变换等方法实现的计数结果图,蓝圈红圈绿圈为找到的位置。

 

 

猜你喜欢

转载自blog.csdn.net/thequitesunshine007/article/details/121050933
今日推荐