2016-09-29 3 views
3

Angenommen, wir arbeiten an einem Bild, gibt es eine Möglichkeit, auf die Pixel innerhalb der Kontur zuzugreifen?OpenCV: Wie finde ich die Pixel innerhalb einer Kontur in C++

Ich habe die Kontur bereits mit der Funktion findContours() gefunden und sogar die Momente gefunden, aber ich konnte die Pixel innerhalb der Kontur nicht finden.

Alle Vorschläge sind willkommen!

Vielen Dank!

+0

Was genau meinen Sie mit "Finden der Pixel"? Definieren Sie Ihr Problem klarer und veranschaulichen Sie noch besser, was Sie meinen, indem Sie ein Beispiel geben. –

+0

Eigentlich bekomme ich die Pixel der Grenze mit der Funktion findContours(), aber ich bin nicht in der Lage, die Pixel innerhalb der Kontur oder Grenze zu bekommen. Ich muss die Pixel ohne Iteration durch das ganze Bild Pixel finden. – Bloklo

+2

Können Sie 'connectedComponents' überhaupt nicht verwenden? – Miki

Antwort

4

Als @Miki bereits erwähnt, können Sie connectedComponents verwenden, um eine Beschriftung durchzuführen. Dann iterieren Sie durch die Begrenzungsbox Ihres Objekts, wie es @Amitay Nachmani vorgeschlagen hat. Aber statt pointPolygonTest die Verwendung können Sie überprüfen, ob der Wert an Ihren aktuellen Positionen entspricht Ihr aktuelles Etikett Hier ist ein kleines Beispiel:

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

     } 
    } 
} 

EDIT:

Seit youre OpenCV mit 2.4 gibt es zwei Möglichkeiten, die gleichen Ergebnisse erzielen. Zuerst können Sie findContours verwenden, um die Blobs zu erkennen, und dann in ein neues Bild mit einer bestimmten Farbe als Beschriftung zeichnen (beachten Sie, dass Ihre Blobs Löcher enthalten könnten). Dann durchlaufen Sie das Bild innerhalb des Begrenzungsrechtecks ​​jeder Kontur und Erhalte alle Punkte mit dem Label deiner aktuellen Kontur. Wenn Sie nur das Begrenzungsrechteck in Ihrem Binärbild durchlaufen, haben Sie Probleme mit Objekten, die das Begrenzungsrechteck überlappen. Hier ist der 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; 
} 

Zweitens können Sie Ihre eigene Etiketten- mit Floodfill durchführen kann. Daher iterieren Sie durch Ihr Bild und beginnen mit der Überfüllung für jedes weiße Pixel, durchlaufen das umgebende Rechteck und erhalten alle Punkte, die dieselbe seedColor haben. Hier ist der Code:

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

mit

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

ich verwendet, um dieses Bild:

enter image description here

Und hier sind die Begrenzungskästen und die Punkte innerhalb der Kontur für die Visualisierung:

enter image description here

+0

Vielen Dank !! @Pschn, ich bekomme ein Problem mit der Aussage, dass "verbundene Komponenten nicht existieren". Ich habe irgendwo gelesen, dass es nur in opencv Version 3.1 verfügbar ist, aber meins ist Version 2.4 ... Und ich lese auch wie opencv 3.1 ist instabil. – Bloklo

+0

In diesem Fall müssen Sie findContours verwenden und das Begrenzungsrechteck berechnen. Ich werde meine Antwort aktualisieren. Aber ich kann dir nicht sagen, ob opencv 3.1 instabil ist, sorry – PSchn

+0

Sicher !! und danke dir! – Bloklo

0

Verwenden Sie den pointPolygonTest http://docs.opencv.org/2.4/modules/imgproc/doc/structural_analysis_and_shape_descriptors.html?highlight=pointpolygontest#pointpolygontest für alle Pixel innerhalb des Begrenzungsrahmens der Konturkontur.

+0

Danke !! aber das wird geben, ob ein Pixel innerhalb der Kontur oder außerhalb oder auf der Kontur ist. Was aber erforderlich ist, ist eine Liste aller Pixel innerhalb der Kontur, so dass ich daraus zufällig ein Pixel für meine weiteren Berechnungen auswählen kann. – Bloklo

+0

Also, wie ich schon sagte, gehe über alle Pixel, die in der Bounding Box des Counters sind, und prüfe nach jedem von ihnen, ob es drinnen ist oder nicht. Wenn ja, fügen Sie es zu einem Vektor von Pixeln, die innerhalb –

+0

sind Ja .. Amitay .. sogar ich dachte so .. aber ich dachte etwas anderes wie, ohne Iteration durch das ganze Bild Pixel, gibt es eine andere Methode, um auf die Pixel zuzugreifen Innerhalb? – Bloklo

Verwandte Themen