首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >如何在OpenCV connectedComponents函数之后分割对象

如何在OpenCV connectedComponents函数之后分割对象
EN

Stack Overflow用户
提问于 2015-10-07 15:56:06
回答 3查看 4.3K关注 0票数 2

我得到了一个带有connectedComponents函数C++ OpenCV的标签,如图中所示:

这是ccLabels变量的输出,它是一个与原始图像大小相同的cv::Mat

所以我要做的是:

  1. 计算每个数字的出现情况,并选择那些发生的次数超过N次数,这是“大”的。
  2. 分割“大”组件的区域,然后计算该区域内的4和0的数量。

我的最终目标是计算图像中的洞数,因此我的目标是从(number of 0's / number of 4's)中推断出洞数。这可能不是最漂亮的方式,但图像是非常均匀的大小和照明,所以它将满足我的需要。

但是我对OpenCV并不熟悉,我不知道如何完成这个任务。

以下是我迄今所做的工作:

代码语言:javascript
运行
复制
cv::Mat1b outImg;
cv::threshold(grayImg, outImg, 150, 255, 0); // Thresholded -binary- image
cv::Mat ccLabels;
cv::connectedComponents(outImg, ccLabels); // Each non-zero pixel is labeled with their connectedComponent ID's
// write the labels to file:
std::ofstream myfile;
    myfile.open("ccLabels.txt");
    cv::Size s = ccLabels.size();
    myfile << "Size: " << s.height << " , " << s.width <<"\n";
    for (int r1 = 0; r1 < s.height; r1++) {
        for (int c1 = 0; c1 < s.height; c1++) {
            myfile << ccLabels.at<int>(r1,c1);
        }
        myfile << "\n";
    }
    myfile.close();

因为我知道如何在矩阵中迭代,所以计数数字应该是可以的,但是首先我必须分离(消除/忽略)“背景”像素,它们是之外的0's 连接的组件。那么数数应该很容易。

我如何分割这些“大”组件?也许可以获得一个掩码,并且只考虑mask(x,y) = 1所在的像素

谢谢你的帮助!

编辑

这是被分割的图像:

这就是我在Canny边缘检测之后得到的结果:

这是实际图像(阈值):

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2015-10-07 18:12:31

这里有一个简单的程序,从你的阈值图像开始,找到骰子上的数字。

  1. 寻找外部轮廓
  2. 对于每个等高线
    • 最后丢弃小水珠
    • 画满面具
    • 使用和和XOR隔离内部孔
    • 再找一次轮廓
    • 数等高线

结果:

代码语言:javascript
运行
复制
Number: 5
Number: 2

图片:

代码:

代码语言:javascript
运行
复制
#include <opencv2\opencv.hpp>
#include <iostream>
#include <vector>
using namespace std;
using namespace cv;

int main(void)
{
    // Grayscale image
    Mat1b img = imread("path_to_image", IMREAD_GRAYSCALE);

    // Minimum area of the contour
    double minContourArea = 10;

    // Prepare outpot
    Mat3b result;
    cvtColor(img, result, COLOR_GRAY2BGR);

    // Find contours
    vector<vector<Point>> contours;
    findContours(img.clone(), contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);

    for (int i = 0; i < contours.size(); ++i)
    {
        // Check area
        if (contourArea(contours[i]) < minContourArea) continue;

        // Black mask
        Mat1b mask(img.rows, img.cols, uchar(0));
        // Draw filled contour
        drawContours(mask, contours, i, Scalar(255), CV_FILLED);

        mask = (mask & img) ^ mask;

        vector<vector<Point>> cntrs;
        findContours(mask, cntrs, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);

        cout << "Number: " << cntrs.size() << endl;

        // Just for showing results
        drawContours(result, cntrs, -1, Scalar(0,0,255), CV_FILLED);
    }

    imshow("Result", result);
    waitKey();

    return 0;
}
票数 3
EN

Stack Overflow用户

发布于 2015-10-07 16:22:37

更简单的方法是findContours方法。您找到内部轮廓并计算它们的面积(因为内部轮廓将是洞)并相应地处理这些信息。

票数 -1
EN

Stack Overflow用户

发布于 2015-10-07 17:44:00

要解决您的第一个问题,请考虑在values.Count中有一组值,即出现的每一个数字。

代码语言:javascript
运行
复制
 int m=0;
    for(int n=0;n<256;n++)
    {
        int c=0;
        for(int q=0;q<values.size();q++)
        {
            if(n==values[q])
            {
                //int c;
            c++;
            m++;
            }
        }

        cout<<n<<"= "<< c<<endl;
    }
    cout<<"Total number of elements "<< m<<endl;

要解决第二个问题,使用find等值线在图像中找到最大的轮廓,在其周围画出包围矩形,然后裁剪它。再次使用上面的代码来计数像素值"4“和"0”。您可以在这里找到它的链接,https://stackoverflow.com/a/32998275/3853072

票数 -1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/32996963

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档