I'm working in a project where fringes are projected against a subject, and a photo is taken. The task is to find the centerlines of the fringes, which represent, mathematically, the 3D curve of intersection between the fringe plane and the subject surface.
The photo is a PNG (RGB), and former attempts used grayscaling then difference thresholding to get a black-and-white, "zebra-like" photography, from which it was easy to find the midpoint of each pixel column of each fringe. The problem is that, by thresholding and also by taking the mean height of a discrete pixel column, we're having some precision loss and quantization, which is not desired at all.
My impression, by looking at the images, is that the centerlines could be more continuous (more points) and smoother (not quantized) if they were detected directly from the non-thresholded image (either RGB or grayscale), by some statistical sweeping method (some flooding / iterative convolution, whatever).
Below is an actual sample image:
Any suggestion would be much appreciated!
Answer
I suggest the following steps:
- Find a threshold to separate the foreground from the background.
- For each blob in the binary image (one zebra stripe), for each
x
, find the weighted center (by pixel intensity) iny
direction. - Possibly, smooth the
y
values, to remove noise. - Connect the
(x,y)
points by fitting some kind of curve. This article might help you. You can also fit a high-level polynomial, though it is worse, in my opinion.
Here is a Matlab code that shows steps 1,2 and 4. I skipped the automatic threshold selection. Instead I chose manual th=40
:
These are the curves that are found by finding the weighted average per column:
These are the curves after fitting a polynomial:
Here is the code:
function Zebra()
im = imread('http://i.stack.imgur.com/m0sy7.png');
im = uint8(mean(im,3));
th = 40;
imBinary = im>th;
imBinary = imclose(imBinary,strel('disk',2));
% figure;imshow(imBinary);
labels = logical(imBinary);
props =regionprops(labels,im,'Image','Area','BoundingBox');
figure(1);imshow(im .* uint8(imBinary));
figure(2);imshow(im .* uint8(imBinary));
for i=1:numel(props)
%Ignore small ones
if props(i).Area < 10
continue
end
%Find weighted centroids
boundingBox = props(i).BoundingBox;
ul = boundingBox(1:2)+0.5;
wh = boundingBox(3:4);
clipped = im( ul(2): (ul(2)+wh(2)-1), ul(1): (ul(1)+wh(1)-1) );
imClip = double(props(i).Image) .* double(clipped);
rows = transpose( 1:size(imClip,1) );
%Weighted calculation
weightedRows = sum(bsxfun(@times, imClip, rows),1) ./ sum(imClip,1);
%Calculate x,y
x = ( 1:numel(weightedRows) ) + ul(1) - 1;
y = ( weightedRows ) + ul(2) - 1;
figure(1);
hold on;plot(x,y,'b','LineWidth',2);
try %#ok
figure(2);
[xo,yo] = FitCurveByPolynom(x,y);
hold on;plot(xo,yo,'g','LineWidth',2);
end
linkaxes( cell2mat(get(get(0,'Children'),'Children')) )
end
end
function [xo,yo] = FitCurveByPolynom(x,y)
p = polyfit(x,y,15);
yo = polyval(p,x);
xo = x;
end
No comments:
Post a Comment