OpenCV:如何在C ++中找到轮廓内的像素 [英] OpenCV : How to find the pixels inside a contour in c++

查看:100
本文介绍了OpenCV:如何在C ++中找到轮廓内的像素的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我们正在处理图像,是否有任何方法可以访问轮廓内的像素?

Suppose if we are working on an image, is there any way to access the pixels inside the contour?

我已经使用findContours()函数找到了轮廓,甚至找到了力矩,但找不到轮廓内的像素.

I have already found the contour using the function findContours() and even found the moments but I couldn't find the pixels inside the contour.

欢迎任何建议!

谢谢!

推荐答案

如@Miki所述,您可以使用connectedComponents进行标记.然后,像@Amitay Nachmani所建议的那样,遍历对象的边界框.但是,您可以检查当前位置的值是否与当前标签匹配,而不是使用pointPolygonTest,这是一个小示例:

As @Miki already mentioned you can use connectedComponents to perform a labeling. Then you iterate through the bounding box of your object like @Amitay Nachmani suggested. But instead of using pointPolygonTest you can check if the value at your current positions matches your current label Here is a small example:

#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
#include <vector>

using namespace cv;
using namespace std;

Mat binary, labels, stats, centroids;
int main()
{   
    Mat src = imread("C:\\Users\\phili\\Pictures\\t06-4.png",0);    
    threshold(src, binary, 0, 255, CV_THRESH_OTSU);
    int nLabels = connectedComponentsWithStats(binary, labels, stats, centroids);
    vector<vector<Point>> blobs(nLabels-1); 
    for (int i = 1; i < nLabels; i++) //0 is background
    {       
        //get bounding rect
        int left =  stats.at<int>(i, CC_STAT_LEFT) ;
        int top = stats.at<int>(i, CC_STAT_TOP);
        int width = stats.at<int>(i, CC_STAT_WIDTH);
        int height = stats.at<int>(i, CC_STAT_HEIGHT);

        blobs[i - 1].reserve(width*height);     
        int x_end = left + width;
        int y_end = top + height;
        for (int x = left; x < x_end; x++)
        {
            for (int y = top; y < y_end; y++)
            {
                Point p(x, y);              
                if (i == labels.at<int>(p))
                {                   
                    blobs[i-1].push_back(p);
                }
            }

        }
    }   
}

由于您使用的是OpenCV 2.4,因此有两种方法可以达到相同的结果. 首先,您可以使用findContours来检测斑点,然后将其绘制(填充)到具有特定颜色作为标签的新图像中(请注意您的斑点可能包含孔),然后遍历每个轮廓的边界矩形内的图像并得到所有点都带有当前轮廓的标签.如果仅遍历二进制图像内的边界矩形,则对象重叠边界矩形会遇到问题. 这是代码:

Since youre using OpenCV 2.4 there are two ways to achieve the same results. First you could use findContours to detect the blobs, then draw them (filled) into a new image with a specific color as label (be aware that your blobs could contain holes) Then iterate through the image inside the bounding rectangle of each contour and get all points with the label of your current contour. If you just iterate through the bounding rectangle inside your binary image, you have problems with objects overlapping the bounding rectangle. Here is the code:

int getBlobs(Mat binary, vector<vector<Point>> & blobs)
{   
    Mat labels(src.size(), CV_32S);     
    vector<vector<Point>> contours;
    vector<Vec4i> hierarchy;            
    findContours(binary, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_NONE);
    blobs.clear();
    blobs.reserve(contours.size());
    int count = 1; //0 is background
    for (int i = 0; i < contours.size(); i++) // iterate through each contour.
    {
        //if contour[i] is not a hole
        if (hierarchy[i][3] == -1)
        {                       
            //draw contour without holes    
            drawContours(labels, contours, i, Scalar(count),CV_FILLED, 0, hierarchy, 2, Point());
            Rect rect = boundingRect(contours[i]);          
            int left = rect.x;
            int top = rect.y;
            int width = rect.width;
            int height = rect.height;           
            int x_end = left + width;
            int y_end = top + height;
            vector<Point> blob;                 
            blob.reserve(width*height);
            for (size_t x = left; x < x_end; x++)
            {
                for (size_t y = top; y < y_end; y++)
                {
                    Point p(x, y);
                    if (count == labels.at<int>(p))
                    {
                        blob.push_back(p);                      
                    }
                }
            }
            blobs.push_back(blob);
            count++;
        }

    }
    count--;    
    return count;
}

第二,您可以使用Floodfill进行自己的标记.因此,您遍历图像并为每个白色像素开始泛洪,遍历边界矩形并获得所有具有相同seedColor的点. 这是代码:

Second you can perform your own labling with floodfill. Therefore you iterate through your image and start floodfill for every white pixel, iterate through the bounding rectangle and get all points that have the same seedColor. Here is the code:

int labeling(Mat binary, vector<vector<Point>> &blobs)
{   
    FindBlobs(binary, blobs);   
    return blobs.size();
}

使用

void FindBlobs(const Mat &binary, vector<vector<Point>> &blobs)
{
    blobs.clear();
    // Fill the label_image with the blobs
    // 0  - background
    // 1  - unlabelled foreground
    // 2+ - labelled foreground
    cv::Mat label_image;
    binary.convertTo(label_image, CV_32FC1);    
    float label_count = 2; // starts at 2 because 0,1 are used already
    for (int y = 0; y < label_image.rows; y++) {
        float *row = (float*)label_image.ptr(y);
        for (int x = 0; x < label_image.cols; x++) {            
            if (row[x] != 255) {
                continue;
            }
            cv::Rect rect;
            cv::floodFill(label_image, Point(x, y), Scalar(label_count), &rect, Scalar(0), Scalar(0), 4 );                  
            vector<Point> blob;
            blob.reserve(rect.width*rect.height);

            for (int i = rect.y; i < (rect.y + rect.height); i++) {
                float *row2 = (float*)label_image.ptr(i);
                for (int j = rect.x; j < (rect.x + rect.width); j++) {
                    if (row2[j] != label_count) 
                    {
                        continue;
                    }
                    blob.push_back(Point(j, i));
                }
            }

            blobs.push_back(blob);
            label_count++;
        }
    }
}

我使用了这张图片:

以下是边界框和轮廓内用于可视化的点:

And here are the bounding boxes and the points inside the contour for visualization:

这篇关于OpenCV:如何在C ++中找到轮廓内的像素的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆