2017-02-09 3 views
1

Ich versuche, einen Durchschnitt von zwei Blobs in OpenCV zu machen. Um das zu erreichen, dass ich Wasserscheide Algorithmus auf dem Bild in der folgenden Art und Weise vorverarbeitet verwenden vorhatte:Wasserscheide Grenzen eng um einen Bereich

cv::Mat common, diff, processed, result; 
cv::bitwise_and(blob1, blob2, common); //calc common area of the two blobs 
cv::absdiff(blob1, blob2, diff);  //calc area where they differ 

cv::distanceTransform(diff, processed, CV_DIST_L2, 3); //idea here is that the highest intensity 
                 //will be in the middle of the differing area 
cv::normalize(processed, processed, 0, 255, cv::NORM_MINMAX, CV_8U); //convert floats to bytes 

cv::Mat watershedMarkers, watershedOutline; 
common.convertTo(watershedMarkers, CV_32S, 1./255, 1); //change background to label 1, common area to label 2 
watershedMarkers.setTo(0, processed); //set 0 (unknown) for area where blobs differ 

cv::cvtColor(processed, processed, CV_GRAY2RGB); //watershed wants 3 channels 
cv::watershed(processed, watershedMarkers); 
cv::rectangle(watershedMarkers, cv::Rect(0, 0, watershedMarkers.cols, watershedMarkers.rows), 1); //remove the outline 

//draw the boundary in red (for debugging) 
watershedMarkers.convertTo(watershedOutline, CV_16S); 
cv::threshold(watershedOutline, watershedOutline, 0, 255, CV_THRESH_BINARY_INV); 
watershedOutline.convertTo(watershedOutline, CV_8U); 
processed.setTo(cv::Scalar(CV_RGB(255, 0, 0)), watershedOutline); 

//convert computed labels back to mask (blob), less relevant but shows my ultimate goal 
watershedMarkers.convertTo(watershedMarkers, CV_8U); 
cv::threshold(watershedMarkers, watershedMarkers, 1, 0, CV_THRESH_TOZERO_INV); 
cv::bitwise_not(watershedMarkers * 255, result); 

Mein Problem mit den Ergebnissen ist, dass die berechnete Grenze ist (fast) immer neben den Bereich für beide Blobs. Hier sind die Bilder:

Eingang Marker (schwarz = 0, grau = 1, weiß = 2) Input markers

Watershed Eingangsbild (Distanztransformation Ergebnis) mit resultierendem Umrisse in rot gezeichnet: watershed input image with drawn outline

Ich würde erwarten, dass die Grenze entlang der maximalen Intensitätsregion der Eingabe verläuft (also entlang der Mitte der abweichenden Fläche). Stattdessen (wie Sie sehen können) geht es meistens um den Bereich, der als 2 markiert ist, mit einem bisschen verschoben, um den Hintergrund zu berühren (markiert als 1). Tue ich hier etwas falsch oder habe ich falsch verstanden, wie die Wasserscheide funktioniert?

+0

siehe [DIESE] (http://stackoverflow.com/questions/31961240/opencv-watershed-segmentation-miss-some-objects?rq=1) –

+0

@JeruLuke dank, aber Das ist es nicht. Mein Hintergrund hat Label 1 und das Objekt 2. – slawekwin

+0

Invertieren Sie die Entfernung transformieren, so dass Punkte weiter entfernt einen kleineren Wert haben. Fügen Sie 'processed = 255 - processed;' nach der 'normalize'-Zeile hinzu. – Miki

Antwort

1

von diesem Bild ab:

enter image description here

Sie können das richtige Ergebnis einfach erhalten eine All-Null Bild Wende Algorithmus übergeben. Die „Becken“ wird dann ebenso von „Wasser“ gefüllt von jedem „Seite“ ausgehend (dann nur daran erinnern, den äußeren Rand zu entfernen, die standardmäßig -1 durch Wasserscheide Algorithmus eingestellt ist):

enter image description here

Code:

#include <opencv2\opencv.hpp> 

using namespace cv; 
using namespace std; 

int main() 
{ 
    Mat1b img = imread("path_to_image", IMREAD_GRAYSCALE); 

    Mat1i markers(img.rows, img.cols, int(0)); 
    markers.setTo(1, img == 128); 
    markers.setTo(2, img == 255); 

    Mat3b image(markers.rows, markers.cols, Vec3b(0,0,0)); 
    markers.convertTo(markers, CV_32S); 
    watershed(image, markers); 

    Mat3b result; 
    cvtColor(img, result, COLOR_GRAY2BGR); 
    result.setTo(Scalar(0, 0, 255), markers == -1); 

    imshow("Result", result); 
    waitKey(); 

    return(0); 
} 
Verwandte Themen