2016-09-29 13 views
3

이미지에서 작업하는 경우 윤곽 내부의 픽셀에 액세스 할 수있는 방법이 있습니까?OpenCV : C++로 윤곽 내부의 픽셀을 찾는 방법

findContours() 함수를 사용하여 이미 컨투어를 찾았으며 순간을 찾았지만 컨투어 내부의 픽셀을 찾을 수 없었습니다.

모든 의견 환영합니다 !!

감사합니다.

+0

"픽셀 찾기"란 정확히 무엇을 의미합니까? 문제를보다 명확하게 정의하고, 예제를 제공함으로써 의미를 더 잘 설명 할 수 있습니다. –

+0

사실, findContours() 함수를 사용하여 경계 픽셀을 가져 왔지만 컨투어 또는 경계 내부의 픽셀을 가져올 수 없습니다. 전체 이미지 픽셀을 반복하지 않고 픽셀을 찾아야합니다. – Bloklo

+2

처음에는'connectedComponents'를 사용할 수 없습니까? – Miki

답변

4

@Miki에서 이미 언급했듯이 연결된 구성 요소를 사용하여 레이블링을 수행 할 수 있습니다. 그런 다음 @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를 사용하여 모양을 감지 한 다음 특정 색상을 레이블로 사용하여 새 이미지에 그립니다 (채우기). 모양에 구멍이있을 수 있음을 인식하십시오. 그런 다음 각 윤곽선의 경계 사각형 안의 이미지를 반복합니다. 현재 윤곽의 라벨로 모든 점을 얻으십시오. 바이너리 이미지 내에서 경계 사각형을 반복하는 경우 경계 사각형과 겹치는 객체에 문제가 발생합니다. 당신이 플러드 필과 함께 자신의 마킹을 수행 할 수 있습니다

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가 동일한 모든 점을 가져옵니다.

enter image description here

그리고 여기에 경계 상자와 시각화를위한 윤곽 내부의 포인트는

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

+0

감사합니다! @PSchn, "연결 구성 요소가 존재하지 않습니다."라는 말을 듣고 있습니다. 나는 opencv 버전 3.1에서만 사용할 수있는 어딘가 읽었지만 2.4 버전은 ... 그리고 opencv 3.1이 불안정한 것처럼 읽었다. – Bloklo

+0

그런 경우 findContours를 사용하여 경계 사각형을 계산해야합니다. 나는 나의 대답을 업데이트 할 것이다. 하지만 opencv 3.1이 불안정한 지 알려주지 못합니다. 죄송합니다. – PSchn

+0

Sure !! 고마워! – Bloklo

0

윤곽선 윤곽의 경계 상자 안의 모든 픽셀에서 pointPolygonTest http://docs.opencv.org/2.4/modules/imgproc/doc/structural_analysis_and_shape_descriptors.html?highlight=pointpolygontest#pointpolygontest을 사용하십시오.

+0

감사합니다 !! 그러나 이것은 픽셀이 윤곽 내부에 있는지 외부 윤곽에 있는지에 관계없이 제공됩니다. 그러나 필요한 것은 윤곽선 내부의 모든 픽셀 목록으로, 이후의 계산을 위해 임의로 픽셀을 선택할 수 있습니다. – Bloklo

+0

그래서 카운터의 경계 상자에있는 모든 픽셀을 살펴보고 내부에 있는지 여부를 확인합니다. 그렇다면 –

+0

안에있는 픽셀 벡터에 추가하십시오. Amitay .. 심지어 그렇게 생각했습니다. 그러나 전체 이미지 픽셀 전체에서 반복하지 않고 다른 것으로 생각합니다. 픽셀에 액세스하는 다른 방법이 있습니다. 내부? – Bloklo

관련 문제