1
$\begingroup$

I have designed a surface with a shape like a rounded rectangle and I want to detect its exact boundaries in a photo I take from it. A sample photo is like this:

Sample image

I have tried thresholding the image but even after a Gaussian smoothing, the threshold won't give me an exact boundary.

Does anyone know of a technique that would give me the precise boundaries, regardless of the issues in lighting, etc?

UPDATE: I'm sorry I didn't state the problem well, and actually I wasn't aware of the real problem (though I think it hasn't changed too much):

Here is the new photo. The photo is taken looking down inside a plastic bucket with a small amount of water inside, and I need to segment the region inside the water from the walls of the bucket, so I can detect the objects inside the water later. There is some lighting illuminating the bottom of the bucket from underneath (actually a sheet of plexiglass is placed instead of the original bottom).

new image

The problem is that the reflections of light on the wall make it the same color as where the water is, in some areas like the bottom-center in the sample image which makes it hard to find the water level.

Also, I would appreciate any hints on how should I differentiate between the boundary related to the plexiglass, and the boundary related to the water level.

Thanks

$\endgroup$
2
$\begingroup$

Behold the power of shortest path.

The solution roughly follows what I did here: Detecting and isolating part of an image.

In this case we first treat the image by limiting every pixel value above the water-level grey to that same intensity.

enter image description here

Then performing shortest path on the inverse edge image created with a difference of Gaussian filter we get:

enter image description here

Resulting in the following segmentation:

enter image description here

My MATLAB functions that are needed for this solution:

http://imageprocessing.com.au/research/code/polarTransform.m http://imageprocessing.com.au/research/code/circularShortestPath.m http://imageprocessing.com.au/research/code/linearShortestPath.m

Code:

clear all
close all

%% Load image
I = imread('CabQx.jpg');
I = double(rgb2gray(I));
figure
imagesc(I);
colormap gray(256); 
title('Image');

%% Adjust intensity
Ia = I;
Ia(Ia > 49) = 49;
figure
imagesc(Ia);
colormap gray(256); 
title('Adjusted Image');

%% Bandpass Kernel
H1 = fspecial('gaussian',[100,100],8); % *** Changed filter size
H2 = fspecial('gaussian',[100,100],2);  % *** 
H = H2-H1;
H = mat2gray(H);
figure;
imagesc(H);
colorbar;
colormap gray(256); 
title('Bandpass kernel');

%% Edge Kernel
Hedge = imag(hilbert(H));
figure;
imagesc(Hedge);
colormap gray(256); 
title('Edge Kernel');

%% Edge filtered image
G = sqrt(imfilter(Ia,Hedge,'replicate').^2 + imfilter(Ia,Hedge.','replicate').^2);
G = max(G(:)) - G;
imagesc(G);
colormap gray(256); 
title('Inverse edge filtered image');

%% Shortest path
% Mid point
[r,c] = size(G);
r = floor(r/2);
c = floor(c/2);
% Min radius and max radius
min_radius = 100;
max_radius = 1000;
% Shortest path
[ path, energy, lastIndex, pathImage ] = ...
    circularShortestPath(G, 100, [c,r], [min_radius,max_radius], [400,720*2]);
figure;
imagesc(I);
hold on;
plot(path(:,1),path(:,2),'r','LineWidth',2);
hold off;
colormap gray(256); 
title('Shortest path');

%% Segment
figure
imagesc(I);
hold on;
fill(path(:,1),path(:,2),'r');
hold off;
colormap gray(256); 
title('Mask')

%%
J = zeros(size(I));
mask = roipoly(J,path(:,1),path(:,2));
segmentedI = I .* mask;
figure;
imagesc(segmentedI);
colormap gray(256); 
title('Segmented image');
$\endgroup$
  • $\begingroup$ That was awesome! I think I'll have a hard time converting it to OpenCV. Is there a reference paper I can read in case I don't understand the code? $\endgroup$ – mrmashal Oct 11 '15 at 8:16
  • $\begingroup$ Have a look at staff.itee.uq.edu.au/lovell/aprs/accv2002/accv2002_proceedings/… $\endgroup$ – geometrikal Oct 11 '15 at 12:11
  • $\begingroup$ In the above code I doubled the image (1/2 image extra patch size in the paper). I'm actually dusting off some old code that does this in Emgu.CV in the next week, so I'll share it soon. $\endgroup$ – geometrikal Oct 11 '15 at 12:12
  • $\begingroup$ Wow! That's very kind of you. $\endgroup$ – mrmashal Oct 11 '15 at 14:19
0
$\begingroup$

Use level sets, or active contours. They are good at handling such problems and typically robust to noise. They're also sub-pixel accurate in certain respect. The best part is that many open source projects exist:

  1. Active Contour Segmentation
  2. Sparse Field Active Contours
  3. Combination of Piecewise-Geodesic Paths
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.