2017-02-09 7 views
1

Я пытаюсь сделать в два раза два капли в OpenCV. Для того, чтобы добиться того, что я планировал использовать водораздел алгоритм на изображении препроцессором следующим образом:Границы водораздела тесно связаны с одной областью

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

Моя проблема с результатами, что расчетная граница (почти) всегда рядом с областью, общей для обоих сгустков. Вот фотографии:

Входные маркеры (черный = 0, серый = 1, белый = 2) Input markers

Водораздел входного изображения (расстояние преобразования результат) с полученной контуром нарисованные красным цветом: watershed input image with drawn outline

Я ожидал бы, что граница пройдет вдоль области максимальной интенсивности входа (то есть вдоль середины разной области). Вместо этого (как вы можете видеть) он в основном идет вокруг области, помеченной как 2, немного сдвинутой, чтобы коснуться фона (отмечена как 1). Я что-то делаю здесь неправильно, или я неправильно понял, как работает водораздел?

+0

см [это] (http://stackoverflow.com/questions/31961240/opencv-watershed-segmentation-miss-some-objects?rq=1) –

+0

@JeruLuke спасибо, но это не так. У моего фона есть метка 1 и объект 2. – slawekwin

+0

Инвертировать преобразование расстояния, чтобы более отдаленные точки имели меньшее значение. Добавьте 'обработано = 255 - обработано;' после строки 'normalize'. – Miki

ответ

1

Начиная с этого изображения:

enter image description here

Вы можете получить правильный результат просто передавая все-ноля изображения водоразделов алгоритма. «таз» затем в равной степени заполнен из «воды» начиная с каждого «сторона» (тогда только не забудьте удалить внешнюю границу, который устанавливается по умолчанию -1 по водоразделу алгоритма):

enter image description here

Код:

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