how to determine the best tangential at every points from a freehand line?
3 views (last 30 days)
Show older comments
Hi all I have an image that consist of a line of pixels that can be from any shape. I'd like to know what would be the best way to calculate the tangential equation at every pixel along that "freehand like" pixel line. My first approximation was to take groups of pixels and make a linear fit but in many cases this method gives bad results.
Thanks in advance for your help.
Image Analyst on 22 Aug 2012
Edited: Image Analyst on 22 Aug 2012
Yep. Been there, done that. I wanted to get the average cross sectional intensity profile along an edge that the user drew along. It's not easy. I could dump about two hundred lines of code on you, but even that calls other functions and I can't explain it all to you. There are some pitfalls that you'll learn about. What I did was to fit a certain number of points (5) around the point in question to a quadratic. The more points I included in the fit, the less the perpendicular line would bounce around as you moved along the curve. With just 2 or 3 points it was waving around wildly. With too many, the perpendicular didn't look very perpendicular to the curve at that point. Five points seemed about right. Then get the slope at the point (the 3rd or middle point), which is the derivative of the quadratic formula at that point. Then get a perpendicular line (with slope = -1/m) and find endpoints for it, then use improfile to get the image profile along that perpendicular line segment. Of course you don't need to get the perpendicular part like I did, just the equation of the quadratic at each point. Here's a real brief snippet of the most crucial part:
% Find the 5 points centered on point p, then fit a curve through them.
% The coefficients in the approximating polynomial of degree 6 are
for pt = 1 : numberOfPointsToFit
x(pt) = boundaryVerticesXCoordinates(int16(p + pt - middlePoint));
y(pt) = boundaryVerticesYCoordinates(int16(p + pt - middlePoint));
t(pt) = pt;
coefficientsX = polyfit(t, x, 2); % Fit 2nd order polynomial.
coefficientsY = polyfit(t, y, 2); % Fit 2nd order polynomial.
slopeX = 2 * coefficientsX(1) * t(middlePoint) + coefficientsX(2);
slopeY = 2 * coefficientsY(1) * t(middlePoint) + coefficientsY(2);
% Check for error - all the x values are the same (vertical curve).
[msgstr, msgid] = lastwarn;
% if strcmpi(msgid, 'MATLAB:polyfit:RepeatedPointsOrRescale')
if slopeX == 0
% Abnormal case: Vertical line.
% Get the fitted value in the middle.
xMiddle = x(middlePoint);
yMiddle = y(middlePoint);
angleInRadians = 3.1415926535 / 2;
% Normal case: slanted line.
% Get the fitted value in the middle.
xMiddle = polyval(coefficientsX, t(middlePoint));
yMiddle = polyval(coefficientsY, t(middlePoint));
slope = slopeY / slopeX;
inverseSlope = 1/slope; % Get slope perpendicular to tangent of curve.
angleInRadians = atan(inverseSlope);
angleInDegrees = angleInRadians * 180 / 3.1415926535;
% Find the endpoints of the perpendicular line.
angles(processedSoFar) = angleInDegrees;
x3 = xMiddle - ROI_HalfWidth * cos(angleInRadians);
y3 = yMiddle + ROI_HalfWidth * sin(angleInRadians);
x4 = xMiddle + ROI_HalfWidth * cos(angleInRadians);
y4 = yMiddle - ROI_HalfWidth * sin(angleInRadians);
profileArrayEndPoints(1, processedSoFar, 1) = x3;
profileArrayEndPoints(1, processedSoFar, 2) = y3;
profileArrayEndPoints(2, processedSoFar, 1) = x4;
profileArrayEndPoints(2, processedSoFar, 2) = y4;
The SMOOTH function from the Curve Fitting Toolbox might help. This seems to work well for me:
h = imfreehand('Closed',false);
P = h.getPosition;
XS = smooth(P(:,1),11,'sgolay',3); % Adjust this as needed
YS = smooth(P(:,2),11,'sgolay',3);
dXS = conv(XS,[-1 0 1]','valid');
dYS = conv(YS,[-1 0 1]','valid');
V = [dXS dYS];
V = bsxfun(@rdivide,V,sqrt(sum(V.^2,2)));
Ryan on 22 Aug 2012
Edited: Ryan on 22 Aug 2012
I have been struggling with a related issue myself as of late.
I settled for sampling the image with a small window and using regionprops() to find orientation of the portions in the smaller window. This tends to bias towards certain angles and does not result in a high sampling count #, but it is pretty effective. I have had some minor success in fitting curves to the lines, but nothing to write home about in terms of an improvement over the prior method.
The issue seems to come down to the low # of points defining the curves (if you think on the pixel level, you're automatically biased to 0,45,90,135, etc degree tangential lines). Interpolating has helped some what, but I've still noticed biases towards certain angles. Perhaps the error is in my implementation though. I have tried using the file exchange submission interparc as well as using interp1 in the two image dimensions, but nothing has been worth the effort thus far.
Find more on Linear and Nonlinear Regression in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!Start Hunting!