原博客为:http://blog.csdn.net/cfqcfqcfqcfqcfq/article/details/53133357,但是原博客算法存在诸多问题,因此这里修改了一下。

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

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

       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;  
}  



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




GitHub 加速计划 / opencv31 / opencv
77.38 K
55.71 K
下载
OpenCV: 开源计算机视觉库
最近提交(Master分支:2 个月前 )
c3747a68 Added Universal Windows Package build to CI. 6 天前
9b635da5 - 6 天前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐