10

I'm using a canny edge detection and a finding contours function (both OpenCV) to create markers for the watershed transform. Everything works fine but I'm not 100% satisfied with the results. The reason is that some edges are missing and therefore important information is lost. In more detail, I got a bunch of windows (front views), which are rectangles, after the watershed transform I end up with something like this:

enter image description here enter image description here but I would rather have nice rectangles, that are complete and not open to one side. While maintaining irregular shapes (bushes in front of the house, cars..) Any ideas how I could solve this problem?I thought about overlaying the whole image with a grid, but I can't make it work.

Thank you very much.

Here is my code:

Mat gray;
cvtColor(im, gray, CV_BGR2GRAY);

// Use Canny instead of threshold to catch squares with gradient shading
Mat bw;
Canny(gray, bw, 0, 100, 5, true);

// Find contours
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;

findContours( bw, contours, hierarchy,
    CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE );


// watershed
Mat markers(bw.size(), CV_32S);
markers = Scalar::all(0);
int idx = 0;
int compCount = 0;
for( ; idx >= 0; idx = hierarchy[idx][0], compCount++ ) {
    if (fabs(contourArea(contours[compCount])) < min_size )
        continue;
    drawContours(markers, contours, idx, Scalar::all(compCount+1), 1, 8, hierarchy, INT_MAX);
}
watershed( im, markers );

As requested, here is the original image, the image I would like to get and my output: enter image description here

And I would like to have a segmentation like this (although over segmentation does not hurt, I just need to make sure, I get all the details):

enter image description here

While I get something like this: enter image description here (please ignore the colours, they are not important for this question and are just a result of my overall program). This is only one example, if you want, I can show you more, also please have a look at the etrims dataset, all my pictures are from there.

user667804
  • 740
  • 6
  • 25
  • 1
    Things like this can heavily depend on the actual source image so you might want to attach one or more examples if you can. – Mario Jan 11 '14 at 10:37
  • added some images, in general I'm using the etrims dataset, which can be found here:http://www.ipb.uni-bonn.de/projects/etrims_db/ – user667804 Jan 11 '14 at 10:56
  • please add input image for your first image also – Abid Rahman K Jan 11 '14 at 13:31
  • I added my output, corresponding to the example images I gave. Please tell me if you need more images – user667804 Jan 11 '14 at 13:56
  • 1
    OpenCV doesn't have a built in segmentation slgorithm. You can look here: https://www.eecs.berkeley.edu/Research/Projects/CS/vision/bsds/ at different algorithms, you'll be able to find open source code for some of them. Regardless of the above, if you decide to implement something yourself start with some kind of bilateral/mean-shift filtering, it will help. – Rosa Gronchi Jan 11 '14 at 17:36
  • 1
    One of the basic problems is the reflection in the windows, and the luminance gradient across the facade. Try using a [GMM](http://en.wikipedia.org/wiki/Mixture_model) to better model these variations. – beedot Jan 19 '14 at 17:30

2 Answers2

7

Two things -

1) As already mentioned, edge detection results in spurious edges being picked up.

2) Using these edges as markers for watershed segmentation results in over-segmentation because every marker produces a segmented region in the output.

Strategy -

(i) Preprocessing: Smooth the image heavily (morphological opening by reconstruction can be used for homogenizing the intensities without significantly affecting edges you are interested in).

(ii) Markers: Instead of using edges as seeds, I'd use the local extrema. Ideally, we want one marker for every region we want segmented.

(iii) Segmentation: Find the gradient magnitude (range filtering is also a good option) of the image from step (i) and use that as the segmentation function.

Using this strategy, I get the following segmentation.

enter image description here

Alternatively, after step (i), you can use Canny edge detection and do some morphological cleanup (to fill contours and remove edges that remain). This is what I get.

enter image description here

These are not exactly the expected segmentation (some objects like the car are not detected), but are a good start.

Edit: The MATLAB code used to generate the images -

% convert to grayscale
img = rgb2gray(origImg);

% create an appropriate structuring element
w_size = 20;
seSquare = strel('square', w_size);

% opening by reconstruction - to smooth dark regions
imgEroded = imerode(img, seSquare);
imgRecon = imreconstruct(imgEroded, img);

% invert and repeat - to smooth bright regions
imgReconComp = imcomplement(imgRecon);
imgEroded2 = imerode(imgReconComp, seSquare);
imgRecon2 = imreconstruct(imgEroded2, imgReconComp);

% get foreground markers
fgm = imregionalmax(imgRecon2);

% get background markers - this step can be skipped 
% in which case only fgm would be the marker image 
% and the segmentation would be different 
distTrans = bwdist(fgm);
wLines= watershed(distTrans);
bgm = wLines == 0;

% get the segmentation function and impose markers
% perform watershed segmentation
seSquare3 = strel('square', 3);
rangeImg = rangefilt(imgRecon2, getnhood(seSquare3));
segFunc = imimposemin(rangeImg, fgm | bgm);
grayLabel = watershed(segFunc);

rgbLabel= label2rgb(grayLabel);
figure, imshow(rgbLabel); title('Output using Watershed')

% alternatively, extract edges from the preprocessed image
% perform morph cleanup
bwEdges = edge(imgRecon2, 'canny');
bwFilled = imfill(bwEdges, 'holes');
bwRegions = imopen(bwFilled, seSquare3);
grayLabel = bwlabel(bwRegions);

rgbLabel = label2rgb(grayLabel, 'jet', 'k');
figure, imshow(rgbLabel); title('Output using Canny')
zepman
  • 671
  • 6
  • 14
  • 1
    Although I posted this over a year ago, the problem was never fully solved so this looks really interesting to me. Could you spare me some time and maybe post your code somewhere? I think the main issue, I'm still having, is that I would miss a lot of objects (cars, ...). I don't mind recognizing a car as multiple objects (over segmentation) but I have to recognize it somehow (not just ignore it). Same with the sky and the street (see referenz image). – user667804 May 14 '15 at 17:45
  • The images were generated using MATLAB code, which I didn't want to post because your code is in C++. Writing the equivalent code using OpenCV doesn't look very difficult, although it requires implementation of the "morphological reconstruction" part. See this - http://answers.opencv.org/question/35224/morphological-reconstruction/. I can edit my answer to include the MATLAB code if you think it'll be helpful. – zepman May 14 '15 at 18:08
  • would be nice if you could link to your code, I would play with it in Matlab before converting it to c++ code. – user667804 May 14 '15 at 19:46
  • Thanks - Played around with it for a while. First of all I think it is a great idea to use morphological opening to get rid of all the noise - not sure why I have to reconstruct the image afterwards? Second I tried some other images and unfortunatly the results were not satisfying (ETrims dataset). I feel like this might only work if I would tune the parameters for each image which is not feasible. There is also a matlab tutorial which I want to take a closer look at (first results look promising). Unfortunatly I don't have a lot of time right now, so it might take me a while to post an update – user667804 May 16 '15 at 02:06
  • In the above technique, the reconstruction is part of the opening operation. In normal opening, erosion is followed by dilation. It's the same in opening by reconstruction, except that the dilation is restricted by a mask image (done by `imreconstruct`). See this - http://blogs.mathworks.com/steve/2008/07/14/opening-by-reconstruction/. It's true that you need extensive parameter tuning, especially when there's variability in your input images. You might have to look into supervised techniques. – zepman May 16 '15 at 14:58
0

from the looks of the desired output and the program's output, it seems that the edge detector is finding spurious edges. Canny edge detector contains a low-pass filter, but it might help for you to do a separate Gaussian low-pass filtering step before you actually run the Canny edge detector.

Other than that, it is difficult to achieve the desired result. For e.g., look at the top-most windows in the picture. They have distinct colors --- the frame, the shadow of the frame, and the window. The boundaries of these colors will be detected as edges by the Edge detector.

ponderingfish
  • 343
  • 1
  • 5
  • 11
  • I tried smoothing the image and also using all 3 colour channels for the edge detection. The results improved slightly. I think for now this will do, but if somebody knows a better way, I would be happy to hear about it. – user667804 Jan 12 '14 at 11:03