2016-09-29 374 views
3

假设我们正在处理图像,有没有办法访问轮廓内的像素?OpenCV:如何在C++中找到轮廓内的像素

我已经找到使用函数findContours()的轮廓,甚至找到了时刻,但我无法找到轮廓内的像素。

任何建议都欢迎!

谢谢!

+0

你是什么意思的“寻找像素”?更清楚地定义你的问题,并通过提供一些例子来更好地说明你的意思。 –

+0

实际上,我通过使用函数findContours()获取边界的像素,但我无法获取轮廓或边界内的像素。 我需要找到没有迭代整个图像像素的像素。 – Bloklo

+2

你不能首先使用'connectedComponents'吗? – Miki

回答

4

由于@Miki已经提到您可以使用connectedComponents执行标签。然后,像@Amitay Nachmani建议的那样遍历对象的边界框。但是,而不是使用pointPolygonTest您可以检查是否在您的当前位置值当前的标签一致这里是一个小例子:

#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来检测blob,然后将它们(填充)绘制为具有特定颜色作为标签的新图像(请注意,您的Blob可能包含空洞)然后遍历每个轮廓的边界矩形内的图像,并使用当前轮廓的标签获取所有点。如果只是遍历二进制图像中的边界矩形,则会遇到与边界矩形重叠的对象的问题。 下面是代码:你可以用floodfill执行自己的labling

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

二。因此,您遍历图像并开始对每个白色像素进行填充,遍历边界矩形并获取所有具有相同seedColor的点。 下面是代码:

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

我用这个形象:

enter image description here

而且这里的边框和轮廓可视化里面的几点:

enter image description here

+0

谢谢! @PSchn,我收到了一些问题,说“连接组件不存在”。我在某处读到它只能在opencv版本3.1中使用,但是我的版本是2.4版本...而且我也像opencv 3.1一样读取不稳定。 – Bloklo

+0

在这种情况下,您需要使用findContours并计算边界矩形。我会更新我的答案。但我不能告诉你,如果opencv 3.1是不稳定的,对不起 – PSchn

+0

当然!谢谢! – Bloklo

0
+0

谢谢!但是这会给出像素是否在轮廓内部或外部或轮廓上。但需要的是,轮廓内的所有像素列表,以便我可以从中随机选择一个像素以供我进一步计算。 – Bloklo

+0

所以就像我说过的所有在计数器的边界框中的像素,并检查它们中的每一个是否在里面。如果是的话,将它添加到 –

+0

中的像素矢量是的.. Amitay ..甚至我认为是这样..但我想的是不同的像,没有遍历整个图像像素,是否有任何其他方法来访问像素内? – Bloklo