Centerline Detection in an Image

Hello,
I have a picture of a white tube against a black backdrop and I need to find a curve that follows the centerline of the tube. Not necessarily an equation for the curve just a graphical representation in a line graph or something. I am very very new to Matlab so I am not sure how to go about doing this.
What I have done so far is make the image in gray scale and then extracted the matrix. What I think I have to do now is find the maximum value in each row of the matrix since the white will have a higher value in the matrix. I cannot figure out how to do this though.
Another way I figured I could accomplish this is by doing a polyfit for each individual row since the values where the tube are appear to follow a quadratic relationship between the edges of the tube and the center. I could then find the maximum of each of of these polynomials and plot that. Again I don't know how to do this and the documentation doesn't help me.
So my main question is how do I find the column location of the maximum value of each row? So I get an output like:
Row | Column
1 12
2 13
3 14
4 13
5 12
6 11
7 10
or:
x=(1:7), y= 12 13 14 13 12 11 10
except obviously there are around 1000 entries for x
Thanks a lot,

 Accepted Answer

Vivek Selvam
Vivek Selvam on 14 Oct 2013
Edited: Vivek Selvam on 14 Oct 2013
With your idea, this should get you started:
h = imread('0001cropped.jpg'); % read image as 3d matrix : H x W x D where D is 3 for RGB
figure(1); subplot(1,2,1); imshow(h) % on the left, plot the image
sumH = sum(h,3); % sum the RGB values of each pixel
maxRsumH = max(sumH,[],2); % find the maximum for each row
ima = zeros(size(maxRsumH)); % create a matrix of size H x W initialized to 0
for i = 1:length(sumH)
ima(i,sumH(i,:) == maxRsumH(i)) = 1; % wherever the maximum occurs change the value to 1
end
figure(1); subplot(1,2,2); spy(ima) % on the right, plot the points (values of 1)

5 Comments

This helped a lot thank you. I then took the transpose of ima and used polyfit to get a very nice function.
Here is another solution I came up with finally. I am very new so excuse me if this is very ugly but it seems to work alright.
I=imread('0001.jpg');
grey=rgb2gray(I);
greyT=transpose(grey);
[maxVal maxInd]=max(greyT(270:475,75:1234));
x=(1:1160);
c=polyfit(x,maxInd,10);
f=polyval(c,x);
figure(1); image(I(75:1234,270:475));
hold on; plot(f,x); hold off; % sets polyfit line on top of original image
Vivek's solution looks similar to the one I had posted prior. Anyway I would not use polyfit() and polyval() at all. That's totally unacceptable unless your line follows a polynomial. The way I'd do it is to first run a Savitky-Golay filter on it. This is like a polynomial but the fit is done within a window that slides along rather than on the whole global signal. This way it will follow the curve much more accurately. You can program this up yourself, or simply use the sgolay() function in the Signal Processing Toolbox. I attached a demo of the Savitky-Golay filter if you want to run it and have both the image and signal processing toolboxes. Okay, that's step 1 and you do that to identify outliers - the other bright things you have in the image that are not part of the actual line you want to follow. Then you do step 2. Remove outliers from the signal. Finally, step 3: run the Savitkzy-Golay filter on the cleaned signal (signal with outliers removed). This will give you sub pixel accuracy. To recap, let me state again: DO NOT USE POLYFIT! (unless you want inaccurate data) Let me know what you think.
Mitchell
Mitchell on 15 Oct 2013
Edited: Mitchell on 15 Oct 2013
I ran the Savitky-Golay filter you attached on the image and just got a white looking picture for all of them, here is the attached "Original Grayscale Image":
It doesnt look very grayscale, was the image supposed to already be in grayscale before I run it through the S-G filter? Or was I supposed to run the filter on the 'ima' signal from Vivek's solution
I'm sorry I didn't make myself clear enough. The Savitzky Golay filter should be run on your vector of centerline locations not on your image . You should not just apply my example to your whole image - that was just the example I used it for. See how I took a single line of pixel values from a row or column of the image and used sgolay()? Well pretend those values were centerline locations instead of gray levels. So you just pass in your centerline locations instead of pixel values. And of course you just have to do it once because you have just one vector - you don't need to do it for every line and every column in the image like I did, because you're not processing the image, you're processing a list of centerline locations. Does that make sense now?
Oh yes I see this now, thanks a lot for your help. Now I just have to figure out how to repeat all this for 2000 images.
Thanks again.

Sign in to comment.

More Answers (1)

Something like this (untested)
[rows, columns, numberOfColorChannels] = size(yourImage);
for row = 1 : rows
thisRow = yourImage(row, :, 2); % Kth row from green channel
[maxValue, indexOfMax(row)] = max(thisRow);
end

Categories

Find more on Images in Help Center and File Exchange

Asked:

on 14 Oct 2013

Commented:

on 15 Oct 2013

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!