2013-06-17 23 views
5

Eingangs Image: enter image description hereErkennen von Clustern von weißen Pixeln in einem Bild mit OpenCV

Erwartete Ausgabe: enter image description here

Ich beabsichtige, drei zu passen (oder eine bestimmte Anzahl von) Polygone (für diesen Fall, Rechtecke) um die "großen" weißen Flecken in diesem Bild zu bezeichnen. Die Rechtecke, die im Ausgabebild gezeichnet werden, entsprechen meiner Wahrnehmung der weißen Regionen. Ich erwarte nicht, dass der Algorithmus mit den gleichen Bouding-Regionen kommt. Was ich mir wünsche, ist, eine Anzahl von engen Polygonen um die Cluster von weißen Pixeln herum anzuordnen.

Meine anfängliche Lösung bestand darin, Konturen für dieses Bild zu finden und ein geschlossenes konvexes Polygon um jede Kontur zu legen, indem ich die konvexe Hülle der Punkte in jeder Kontur finde.

Da die weißen Bereiche jedoch stark fragmentiert sind und schwarze Bereiche innerhalb der Kanten aufweisen, ist die Anzahl der von cv2.findContours zurückgegebenen Konturen sehr hoch (etwa 500 oder so). Aus diesem Grund verbessert das Anpassen einer konvexen Hülle die Form der weißen Bereiche nicht. Die weißen Bereiche behalten meist ihre ursprünglichen abstrakten Formen bei. Mein Ziel wäre es, die vielen kleinen Konturen einer weißen Region zu einem Ganzen zusammenzufassen, das eine Kontur enthält, über die ich dann eine konvexe Hülle anbringen kann.

Wie löse ich dieses Problem? Soll ich an den Konturpunkten zunächst einen Clustering-Algorithmus verwenden, um die nahe beieinander liegenden Konturen zu finden?

+0

http://en.wikipedia.org/wiki/DBSCAN helfen können. unter Python Scikit. Demo hier http://scikit-learn.org/stable/auto_examples/cluster/plot_dbscan.html – baci

Antwort

1

Sie könnten Kmeans-Clustering mit der x-Koordinate als Feature für jeden Weißpunkt und drei Cluster verwenden. Nehmen Sie dann die konvexe Hülle der resultierenden drei Cluster. Sie müssen möglicherweise verschiedene Startpunkte ausprobieren und das beste Ergebnis auswählen.

2

Sie könnten das Bild zuerst dehnen, bevor Sie Konturen finden. Dilation bewirkt, dass helle Regionen wachsen. Sie können sich vorstellen, dass weiße Pixel um jedes vorhandene weiße Pixel in Ihrem Bild hinzugefügt werden. Auf diese Weise werden die benachbarten hellen Formen zusammengeführt. Siehe http://docs.opencv.org/doc/tutorials/imgproc/erosion_dilatation/erosion_dilatation.html

Sie können auch wieder Weichzeichnen und Schwellwert verwenden, aber die Weichzeichnung kann je nach Unschärfe viel kostspieliger sein als die Dilatation.

3

Zuerst müssen Sie morphologisch-Schließen (das ist Dilatation gefolgt von Erosion) auf diesem Bild durchführen. Dadurch werden alle kleinen "Löcher" Ihres Bildes geschlossen und die Form und Größe der einzelnen Komponenten erhalten. Im Gegensatz dazu, wenn auf die Erosion eine Dilatation folgt, werden die verrauschten Punkte im Bild entfernt. Ich arbeite an einem ähnlichen Bild und musste Dilatation + Erosion bis zu 10 Mal durchführen, um meine Komponenten zu glätten. Nachdem Sie es getan haben, verwenden Sie verbundene Komponenten oder finden Sie Konturen. Dies wird sicherlich die Konturanzahl von 400 auf 20-30 heruntersetzen.

Zweitens haben Sie erwähnt, dass Sie 3 Cluster benötigen. Obwohl die zwei kleinen Cluster (die von der roten Linie bedeckt sind) zu einer Einheit verschmolzen sein könnten. Was ich daraus gemacht habe, war, dass jeder Cluster so eng wie möglich in sein begrenzendes Rechteck passt. Also würde ich vorschlagen, dass Sie eine Schwelleneffizienz (sagen wir 80%) setzen und hierarchisches Clustering verwenden, um jede verbundene Komponente zu einem Cluster zusammenzuführen. Wenn Ihre weißen Pixel weniger als 80% des Raums ihres Begrenzungsrechtecks ​​(eines Clusters) ausnutzen, würden Sie das Clustering stoppen und die Cluster erhalten.

0

Sie können angenäherte Konturen um Ihre Formen zeichnen, bis alle benötigten Regionen verbunden sind. Damit erodiere ich effektiv das Bild. Wenn Sie eine Hülle um diese verbundenen Regionen zeichnen, erhalten Sie Ihre roten Rechtecke.

nur wiederholen, bis die größten drei Rümpfen einige erforderliche Eigenschaft haben (zum Beispiel, wenn sie 99% aller weißen Punkte abdecken)

#include <vector> 
using std::vector; 
#include <algorithm> 
using std::sort; 
#include <string> 
using std::string; 
using std::to_string; 
#include <iostream> 
using std::clog; 
using std::endl; 
#include <opencv2/opencv.hpp> 
using namespace cv; 

int main() 
{ 
    typedef vector<Point> Polygon; 
    typedef vector<Polygon> Polygons; 
    Mat mFrame; 
    Mat mOrig; 
    mFrame = imread("R2TsZ.png"); 
    mFrame.copyTo(mOrig); 
    Mat mOrigHull; 
    Mat mOut; 
    int fileCounter = 0; 
    while(true){ 
    clog<< "image read"<< endl; 
    cvtColor(mFrame, mOut, CV_BGR2GRAY); 
    clog<< "image grayscaled"<< endl; 
    Polygons contours; 
    Polygons aContours; 
    Polygons hulls; 
    OutputArray hierarchy = {}; 

    findContours(mOut, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE); 
    clog<< contours.size()<< " contours found"<< endl; 
    sort(contours.begin(), contours.end(), [](auto p1, auto p2){ 
     return contourArea(p1) > contourArea(p2); 
    }); 
    clog<< "contours sorted"<< endl; 
    aContours.resize(contours.size()); 
    hulls.resize(contours.size()); 
    for(size_t i = 0; i < aContours.size() - 1; ++ i){ 
     approxPolyDP(contours[i], aContours[i], 20, true); 
     drawContours(mFrame, aContours, i, Scalar(255, 255, 255), 10); 
     convexHull(aContours[i], hulls[i], true); 
    } 
    mOrig.copyTo(mOrigHull); 
    for(size_t i = 0; i < 3; ++ i){ 
     drawContours(mOrigHull, hulls, i, Scalar(0, 0, 255), 10); 
    } 
    imshow("out", mOrigHull); 
    int key = waitKey() & 0xff; 
    if(key == 27){ 
     return EXIT_SUCCESS; 
    } 
    if(key == 'p'){ 
     string file = "test_" + to_string(++ fileCounter) + ".png"; 
     imwrite(file, mOrigHull); 
     clog<< file<< " saved."<< endl; 
    } 
    } 
} 

Sehen Sie mehr in diesem tutorial von opencv.

enter image description here