https://answers.opencv.org/question/87583/detach-blobs-with-a-contact-point/
一、问题描述
Detach blobs with a contact point
Detach blobs with a contact point
带 有接触点的斑点时遇到问题,需要从上图中区分出每一个物件。最后能够得到类似这样的结果:
Detach blobs with a contact point
 
Detach blobs with a contact point
二、难点分析
Detach blobs with a contact point
 
Detach blobs with a contact point
简单2值化后会发现主要存在2个问题:1个是存在粘连的情况; 1个是目标物体不是全部一样的,有两个洞的情况、有一个洞的情况。
三、可行建议
1、A basic idea based on morphological operations and distance transformation( 代码1)
Detach blobs with a contact point
Detach blobs with a contact point
 
主要是通过距离变化,能够将这三个物件区分开来,虽然解决了粘连问题,但是在形态学变化的过程中,孔洞的信息丢失掉了;虽然可以使用findblobs等方法找到孔洞,但是孔洞和物件之间的连接信息也肯定会丢掉。
2、基于凸性缺陷的试用代码为您提供了一些关键点(代码2)
Detach blobs with a contact point
Detach blobs with a contact point
3、它进一步进行了优化(代码3)
这里就是能够将缺陷的部分给检测出来了,方便后面进行分割。
四、小结反思
这个例子并没有给出完整的解答,最大的价值在于说明了“通过轮廓缺陷检测的方法解决粘连问题”的思路和方法。
代码1:
# include  "pch.h"
# include  <iostream >
# include  <string >
# include  <cstring >
# include  <cstdlib >
# include  <vector >
# include  "gocvhelper.h" using  namespace std; using  namespace cv; //2020年11月8日10:26:09 //ssd 流水线文件 int main( int argc,  char  *argv[])
{ // Load your image
    cv : :Mat src  = cv : :imread( "e:/template/twoblobs_1.bmp"); // Check if everything was fine if ( !src.data) return  - 1; // Show source image
    cv : :imshow( "src", src); // Create binary image from source image
    cv : :Mat gray;
    cv : :cvtColor(src, gray,COLOR_BGR2GRAY); //cv::imshow("gray", gray); // Obtain binary image
    Mat bw;
    cv : :threshold(gray, bw,  40255, cv : :THRESH_BINARY_INV |cv : :THRESH_OTSU);
    cv : :imshow( "bin", bw); // Erode a bit 
    Mat kernel  = Mat : :ones( 33, CV_8UC1);    
    erode(bw, bw, kernel); //imshow("erode", bw); // Perform the distance transform algorithm 
    Mat dist;    
    distanceTransform(bw, dist, cv : :DIST_L2,  5); // Normalize the distance image for range = {0.0, 1.0}  // so we can visualize and threshold it    
    normalize(dist, dist,  01., NORM_MINMAX);    
    imshow( "distTransf", dist); // Threshold to obtain the peaks // This will be the markers for the foreground objects
    threshold(dist, dist, . 51., cv : :THRESH_BINARY); // Dilate a bit the dist image, this can be optional since in // other use case might cause problems. Here though it works quite well
    Mat kernel1  = Mat : :ones( 55, CV_8UC1);
    dilate(dist, dist, kernel1, Point( - 1- 1),  2);
    imshow( "peaks", dist); // Create the CV_8U version of the distance image // It is needed for findContours()
    Mat dist_8u;
    dist.convertTo(dist_8u, CV_8U); // Find total markers
    vector <Vec4i > hierarchy;
    vector <vector <Point >  > contours;
    findContours(dist_8u, contours, hierarchy, cv : :RETR_TREE,cv : :CHAIN_APPROX_SIMPLE); // Find the rotated rectangles
    vector <RotatedRect > minRect(contours.size()); for (size_t i  =  0; i  < contours.size(); i ++)
    {
        minRect[i]  = minAreaRect(Mat(contours[i]));
    }
    RNG rng( 12345); for (size_t i  =  0; i  < contours.size(); i ++)
    {
        Scalar color  = Scalar(rng.uniform( 0255), rng.uniform( 0255), rng.uniform( 0255)); // contour
        drawContours(src, contours,  static_cast < int >(i), color,  18, vector <Vec4i >(),  0, Point()); // rotated rectangle
        Point2f rect_points[ 4]; minRect[i].points(rect_points); for ( int j  =  0; j  <  4; j ++)
            line(src, rect_points[j], rect_points[(j  +  1%  4], color,  18);
    } /* From here you can extract the orientation of each object by using
    * the information that you can extract from the contours and the
    * rotate rectangles. For example, the center point, rectange angle, etc...
    */

    cv : :imshow( "result", src);
    waitKey( 0); return  0;
}
代码2:
# include  "pch.h"
# include  <iostream >
# include  <string >
# include  <cstring >
# include  <cstdlib >
# include  <vector >
# include  "gocvhelper.h" using  namespace std; using  namespace cv; //2020年11月8日10:26:09 //ssd 流水线文件 int main( int argc,  char  *argv[])
{ // Load your image
    cv : :Mat src  = cv : :imread( "e:/template/twoblobs_1.bmp"); if (src.empty()) return  - 1;
    Mat bw;
    cvtColor(src, bw, COLOR_BGR2GRAY);
    bw  = bw  <  60; // Find contours
    vector <vector <Point >  > contours;
    vector < int > contoursHull;
    vector <Vec4i > defects;
    findContours(bw, contours, RETR_EXTERNAL, CHAIN_APPROX_NONE); for (size_t i  =  0; i  < contours.size(); i ++)
    { if (contourArea(contours[i])  >  500)
        {
            approxPolyDP(contours[i], contours[i],  9true); //多边形拟合
            convexHull(contours[i], contoursHull,  true); //寻找凸包
            convexityDefects(contours[i], contoursHull, defects); //计算缺陷 for (size_t j  =  0; j  < defects.size(); j ++)
            {
                Vec4i defpoint  = defects[j];
                circle(src, contours[i][defpoint[ 2]],  2, Scalar( 02550),  1);
            }
        }
    }
    imshow( "result", src);
    waitKey(); return  0;
}
代码3:
# include  "pch.h"
# include  <iostream >
# include  <string >
# include  <cstring >
# include  <cstdlib >
# include  <vector >
# include  "gocvhelper.h" using  namespace std; using  namespace cv; //2020年11月8日10:26:09 //ssd 流水线文件 int main( int argc,  char  *argv[])
{ // Load your image
    cv : :Mat src  = cv : :imread( "e:/template/twoblobs_1.bmp"); if (src.empty()) return  - 1;
    Mat bw;
    cvtColor(src, bw, COLOR_BGR2GRAY);
    bw  = bw  <  60; // Find contours
    vector <vector <Point >  > contours;
    vector < int > contoursHull;
    vector <Vec4i > defects;
    findContours(bw.clone(), contours, RETR_EXTERNAL, CHAIN_APPROX_NONE); for (size_t i  =  0; i  < contours.size(); i ++)
    { if (contourArea(contours[i])  >  500)
        {
            approxPolyDP(contours[i], contours[i],  2true);
            convexHull(contours[i], contoursHull,  true);
            convexityDefects(contours[i], contoursHull, defects); for (size_t j  =  0; j  < defects.size(); j ++)
            {
                Vec4i defpoint  = defects[j];
                Point pt  = contours[i][defpoint[ 2]];  // get defect point
                Rect r3x3(pt.x  -  2, pt.y  -  255);  // create 5x5 Rect from defect point // maybe no need but to be sure that the rect is in the image
                r3x3  = r3x3  & Rect( 00, bw.cols, bw.rows); int non_zero_pixels  = countNonZero(bw(r3x3));
                cout  << non_zero_pixels  << endl; if (non_zero_pixels  >  17)
                    circle(src, contours[i][defpoint[ 2]],  2, Scalar( 02550),  1);
            }
        }
    }
    imshow( "result", src);
    waitKey(); return  0;
    waitKey(); return  0;
}
代码4
Here's the code for the axes and the curve:
// Drawing orientation angle float angle = -rod.orientation; float length = rod.length / 5;
ellipse(image, rod.barycenter, Size(rod.length / 6,rod.length / 6), 0, 0, -rod.orientation, Scalar( 0, 0, 255));
Point2f P2;
P2.x =  (rod.barycenter.x + length * cos(angle * CV_PI / 180. 0));
P2.y =  (rod.barycenter.y + length * sin(angle * CV_PI / 180. 0));
arrowedLine(image, rod.barycenter, P2, Scalar( 255, 255, 255));
P2.x =  (rod.barycenter.x + length * cos( 0));
P2.y =  (rod.barycenter.y + length * sin( 0));
arrowedLine(image, rod.barycenter, P2, Scalar( 0, 0, 255));

相关文章:

  • 2021-05-29
  • 2021-11-11
  • 2021-11-15
  • 2021-09-07
  • 2021-09-05
  • 2021-10-22
  • 2021-06-11
  • 2021-12-31
猜你喜欢
  • 2021-07-17
  • 2021-10-29
  • 2021-10-24
  • 2022-03-03
  • 2021-06-14
  • 2021-07-03
  • 2021-11-29
相关资源
相似解决方案