zoukankan      html  css  js  c++  java
  • Detach blobs with a contact point

    https://answers.opencv.org/question/87583/detach-blobs-with-a-contact-point/
    一、问题描述
    image descriptionimage description
    有接触点的斑点时遇到问题,需要从上图中区分出每一个物件。最后能够得到类似这样的结果:
    image description image description

    二、难点分析
    image description image description
    简单2值化后会发现主要存在2个问题:1个是存在粘连的情况; 1个是目标物体不是全部一样的,有两个洞的情况、有一个洞的情况。

    三、可行建议
    1、A basic idea based on morphological operations and distance transformation(代码1)
     
    主要是通过距离变化,能够将这三个物件区分开来,虽然解决了粘连问题,但是在形态学变化的过程中,孔洞的信息丢失掉了;虽然可以使用findblobs等方法找到孔洞,但是孔洞和物件之间的连接信息也肯定会丢掉。
    2、基于凸性缺陷的试用代码为您提供了一些关键点(代码2)
    image descriptiondefects.png
    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));




  • 相关阅读:
    让我们一起Go(八)
    让我们一起Go(七)
    让我们一起Go(六)
    VTemplate模板引擎的使用入门篇
    超时时间已过或服务器未响应的解决方法
    SQL Server 2005使用BCP命令将数据表导出到Excel第一行包括表头
    VTemplate模板引擎的使用进阶篇
    VTemplate模板引擎的使用认识篇
    免费开源的模板引擎VTemplate
    .NET 4.5 中新提供的压缩类
  • 原文地址:https://www.cnblogs.com/jsxyhelu/p/14014506.html
Copyright © 2011-2022 走看看