欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

【opencv】凹点切分,种子计数,细胞计数前提 17/7/25更新

程序员文章站 2024-03-08 14:03:16
...

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

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

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

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

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

       3、提取凹区域的轮廓

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

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

       6、基于该两个凹点分割


算法所达到的效果:

【opencv】凹点切分,种子计数,细胞计数前提 17/7/25更新

【opencv】凹点切分,种子计数,细胞计数前提 17/7/25更新

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



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

【opencv】凹点切分,种子计数,细胞计数前提 17/7/25更新【opencv】凹点切分,种子计数,细胞计数前提 17/7/25更新【opencv】凹点切分,种子计数,细胞计数前提 17/7/25更新