如何在OpenCV connectedComponents函数之后对对象进行分段

时间:2015-10-07 15:56:07

标签: c++ opencv image-segmentation

我已经使用C ++ OpenCV的connectedComponents函数获得了一个标签,如图所示:

enter image description here

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

所以我需要做的是:

  1. 计算每个数字的出现次数,然后选择那些数字 发生超过N次,这是"大"的。
  2. 细分 "大"的区域组件,然后计算4和的数量 在该区域内0。
  3. 我的最终目标是计算图像中的孔数,因此我的目标是从(number of 0's / number of 4's)推断出孔的数量。这可能不是最漂亮的方式,但图像在大小和照明方面非常均匀,因此它将满足我的需求。

    但我是OpenCV的新手,我不知道如何完成这项任务。

    这是我到目前为止所做的:

    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();
    

    由于我知道如何在矩阵内部进行迭代,因此计算数字应该没问题,但首先我要分离(消除/忽略)&#34;背景&#34;像素,它们是连接组件的0 <。然后计算应该很容易。

    我如何细分这些&#34;大&#34;组件?也许获得一个掩码,只考虑mask(x,y) = 1

    的像素

    感谢您的帮助!

    修改

    这是阈值图像:

    enter image description here

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

    enter image description here

    这是实际图像(阈值): enter image description here

3 个答案:

答案 0 :(得分:2)

这是一个简单的程序,可以从您的阈值图像中找到骰子上的数字

  1. 查找外部轮廓
  2. 每个轮廓
    • 最终弃掉小斑点
    • 绘制填充的面具
    • 使用AND和XOR隔离内部孔
    • 再次找到轮廓
    • 计算轮廓
  3. 结果:

    Number: 5
    Number: 2
    

    图像:

    代码:

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

答案 1 :(得分:0)

要解决第一个问题,请考虑在值中有一组值。计算出现的每个数字的出现次数。

 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;

要解决第二个问题,请使用findcontours找到图像中最大的轮廓,在其周围绘制边界矩形,然后裁剪它。再次使用上面的代码来计算像素值&#34; 4&#34;和&#34; 0&#34;。您可以在此处找到https://stackoverflow.com/a/32998275/3853072

的链接

答案 2 :(得分:-1)

更简单的方法是使用findContours方法。您可以找到内部轮廓并计算它们的面积(因为内部轮廓将是孔)并相应地处理此信息。