https://answers.opencv.org/question/87583/detach-blobs-with-a-contact-point/

一、问题描述
带有接触点的斑点时遇到问题,需要从上图中区分出每一个物件。最后能够得到类似这样的结果:
 

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

三、可行建议
1、A basic idea based on morphological operations and distance transformation(代码1)
 
主要是通过距离变化,能够将这三个物件区分开来,虽然解决了粘连问题,但是在形态学变化的过程中,孔洞的信息丢失掉了;虽然可以使用findblobs等方法找到孔洞,但是孔洞和物件之间的连接信息也肯定会丢掉。
2、基于凸性缺陷的试用代码为您提供了一些关键点(代码2)
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, 40, 255, cv::THRESH_BINARY_INV|cv::THRESH_OTSU);
    cv::imshow("bin", bw);
    // Erode a bit 
    Mat kernel = Mat::ones(3, 3, 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, 0, 1., NORM_MINMAX);    
    imshow("distTransf", dist);
    // Threshold to obtain the peaks
    // This will be the markers for the foreground objects
    threshold(dist, dist, .5, 1., 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(5, 5, 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(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
        // contour
        drawContours(src, contours, static_cast<int>(i), color, 1, 8, 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, 1, 8);
    }
    /* 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], 9, true);//多边形拟合
            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(0, 255, 0), 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], 2, true);
            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 - 2, 5, 5); // create 5x5 Rect from defect point
                // maybe no need but to be sure that the rect is in the image
                r3x3 = r3x3 & Rect(0, 0, 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(0, 255, 0), 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));

Detach blobs with a contact point的更多相关文章

  1. Detach Volume 操作 - 每天5分钟玩转 OpenStack(55)

    上一节我们成功地通过 attach 操作为 instance 添加了 volume,而与之相对的操作是 detach,就是将 volume 从 instance 上卸载下来. 下图是 Detach 操 ...

  2. jQuery之empty、remove、detach

    三者都有把元素移除的作用,但细微的差别,造就了它们的使命不同. 最权威的解释当然是jQuery_API咯,下面是API中关于他三儿的部分截取. 一.empty: This method removes ...

  3. 2014 Visual Studio Contact(); 直播笔记

    昨天微软干了几件了不起的事:.NET开发环境将开源.跨平台支持(Mac OS X和Linux).多设备支持(WP.Android和iOS)和Visual Studio免费(Visual Studio ...

  4. GConf error:Failed to contact configuration server

    Linux系统运行一直正常,但是图形界面使用root账号登录时遇到下面错误,第一次遇到这么怪异的状况 具体错误信息如下所示: GConf error:Failed to contact configu ...

  5. 【USACO 3.1】Contact(01子串按出现次数排序)

    题意:给你一个01字符串,将长度为a到b之间(包含a.b)的子串按照出现次数排序.注意输入输出格式 题解:01子串对应一个二进制,为了区别11和011这样的不同子串,我们把长度也记录下来,官方题解是在 ...

  6. Contact项目梳理

    1. 共三张表:user用户表  group分组表 contact联系人表 entity  分模块,三个实体类,三个模块 2. 先注册再登录 DAO:UserDAOImpl public User g ...

  7. 01 选择 Help > Install New Software,在出现的对话框里,点击Add按钮,在对话框的name一栏输入“ADT”,点击Archive...选择离线的ADT文件,contact all update ....千万不要勾选点击Add按钮,在对话框的name一栏输入“ADT”,点击Archive...选择离线的ADT文件,contact all update ....千万不要勾

    引言 好久没碰过android,今天重新搭建了一次环境,遇到的问题记录下载.共以后使用. 安装 软件的软件有jdk+eclipse+adt+sdk 主要记录安装adt和sdk的过程,注意,adt和sd ...

  8. Spring-JDBC实现Contact的CRUD

    Spring-JDBC完成Contact的CRUD. 两点注意: 1.log4j.properties文件不能少 2.注意导入的包之间的依赖关系以及版本要求. 项目结构: 主要文件: 建表脚本: CR ...

  9. Account problem-There may be a problem with your account. Please contact us. Sign out

    很多人在使用开发者账号AppleID的时候,都会碰到如下问题 There may be a problem with your account. Please contact us. 登录到苹果的开发 ...

随机推荐

  1. uni-app 支持第三方 H5 离线包

    uni-app 支持第三方 H5 离线包 https://uniapp.dcloud.io/ https://github.com/dcloudio/uni-app refs xgqfrms 2012 ...

  2. React Hooks 内部实现原理

    React Hooks 内部实现原理 源码分析 // 链表 React Hooks 原理剖析 refs https://reactjs.org/docs/hooks-intro.html https: ...

  3. C++ 中的智能指针-基础

    简介 在现代 C++ 编程中,标准库包含了智能指针(Smart pointers). 智能指针用来确保程序不会出现内存和资源的泄漏,并且是"异常安全"(exception-safe ...

  4. 11月16日NGK公链第13期官方快讯!

  5. 微信附近的人,用redis也能实现?(GEO)

    相信微信附近的人的功能大家都应该用过 我可以很随意的通过我自己的定位能看到我附近的人,并且能看到那个人距离我的距离,大家有没有思考过这个是怎么实现的? 作为一个程序猿任何问题应该都有一个思考的过程,而 ...

  6. C++算法代码——纪念品分组[NOIP2007 普及组]

    题目来自:http://218.5.5.242:9018/JudgeOnline/problem.php?id=1099 https://www.luogu.com.cn/problem/P1094 ...

  7. ToolBar 用法

    xml中的设置: <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_wi ...

  8. 图片居中的flex实现

    文本居中 text-align:center; 如果是图片放在div中,就没办法了.用flex可以很简单实现. display: flex; justify-content: center; /* 图 ...

  9. 频繁的或者大范围的来实现数据的共享要使用Vuex

    一. Vuex 概述 1.1 组件之间共享数据的方式 由于使用频繁,通常将v-bind:属性名=" "的格式简写成:属性名=" ".兄弟组件之间的共享即不相干组 ...

  10. (报错解决)Exception encountered during context initialization

    转: (报错解决)Exception encountered during context initialization 关键词 JavaEE JavaWeb eclipse XML AspectJ ...