On Apr 30, 12:43 pm, "Alfonso " <alfonso0...@hotmail.it> wrote:
> I had your same idea 2 days ago, but I'm not able to implement it in Matlab.
> Can you give me a piece of code to do that, starting from the coordinates of the centerline?
> However I don't have to compute the width of the vessel. I just have to save the set of coordinates of the 2 edges (the left and the right one to the centerline) of the vessel.
> Cheers,
>
> Alfonso
------------------------------------------------------------------------------------------------
Well here it is. It's about 200 lines. There are some functions you
won't need like alignProfiles because it doesn't apply to your
situation (I was trying to go along an edge). Good luck!
% IMPORTANT: The newsreader may break long lines into multiple lines.
% Be sure to join any long lines that got split into multiple single
lines.
% These can be found by the red lines on the left side of your
% text editor, which indicate syntax errors, or else just run the
% code and it will stop at the split lines with an error.
function [polyROIXCoords polyROIYCoords] = AnalyzeSingleImage(handles,
imgOriginal, ROI_HalfWidth)
% Get profileArray from the global workspace.
global profileArray;
global boundaryVerticesXCoordinates;
global boundaryVerticesYCoordinates;
axes(handles.axesImage); % Switch current figure back to image
box.
plot(boundaryVerticesXCoordinates, boundaryVerticesYCoordinates, 'b',
'linewidth', 2);
% Clear old overlays from image.
% ClearLinesFromAxes(handles);
% Make the panel visible.
set(handles.pnlCharts, 'Visible', 'on');
profileSpacing = 1;
pStart = profileSpacing + 1;
pEnd = length(boundaryVerticesXCoordinates);
axes(handles.axesPlot); % Switch current figure back to the plot.
ClearLinesFromAxes();
numberOfPointsToFit = int16(7); % Number of points along the curve to
fit a quadratic to.
middlePoint = int16(ceil(numberOfPointsToFit / 2));
% Make sure we don't get points so close to the ends of the curve
that we can't get our
% regression quadratic fit to them.
if pStart < middlePoint
pStart = middlePoint;
end
if pEnd > length(boundaryVerticesXCoordinates) - middlePoint
pEnd = length(boundaryVerticesXCoordinates) - middlePoint;
end
% Initialize some stuff.
numberOfProfiles = 0;
for p = pStart : profileSpacing : pEnd
numberOfProfiles = numberOfProfiles + 1;
end
angles = zeros(numberOfProfiles,1);
profileArrayEndPoints = zeros(2, numberOfProfiles, 2);
hold off; % Let first profile autoscale the Y axis.
if ~isempty(boundaryVerticesXCoordinates)
% Do this if there has been a curve drawn.
x = zeros(numberOfPointsToFit, 1);
y = zeros(numberOfPointsToFit, 1);
t = zeros(numberOfPointsToFit, 1);
processedSoFar = 0;
for p = pStart : profileSpacing : pEnd
processedSoFar = processedSoFar + 1;
set(handles.txtInfo, 'string', ['Processing profile #'
num2str(processedSoFar) ' of ' num2str(numberOfProfiles)]);
drawnow;
% For every profileSpacing pixels along the curve, determine a
perpendicular line,
% and then get the profile along that line.
% 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;
end
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);
% coefficients = polyfit(x, y, 2); % Fit 2nd order polynomial.
% 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;
else
% 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);
end
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;
% We may need to swap the line depending on which side of the line
it starts on.
% They can start on different sides of the line depending on the
curvature of the line
% in that region. For consistency, we need to have them all start
on the same side of
% the line.
if p == pStart
lastLine.x3 = x3;
lastLine.x4 = x4;
lastLine.y3 = y3;
lastLine.y4 = y4;
end
% Get flipped values if necessary.
[x3 x4 y3 y4] = FlipLineIfNecessary(x3, x4, y3, y4, lastLine);
% Save those endpoints for next time.
lastLine.x3 = x3;
lastLine.x4 = x4;
lastLine.y3 = y3;
lastLine.y4 = y4;
% Plot the perpendicular line over the image.
axes(handles.axesImage); % Switch current figure back to the image.
plot([x3 x4], [y3 y4], 'g');
% Get the profiles along the perpendicular line.
numberOfSamples = round(ROI_HalfWidth * 2);
% Get the profile along the perpendicular line in the original
image.
[xCoords, yCoords, lineProfile, xi,yi] = improfile(imgOriginal, [x3
x4], [y3 y4], numberOfSamples);
% Each individual profile needs to be offset so that the valley
bottom is at zero.
% This is to account for variations in height that may occur along
the valley nadir.
minValue = min(lineProfile);
% Offset so that the nadir is at 0.
lineProfile = lineProfile - minValue;
% Align the array so that the half-way point is at the middle of
the profile array.
[alignedArray delta valleyCenter] = AlignProfile(lineProfile);
% Find out which elements are > 0. Elements which are zero didn't
have any fibers in
% them and we shouldn't include them in the average.
nonZeroElements = (alignedArray > 0);
% Accumulate the non-zero elements of the profile (i.e., those that
have data in them)
% into the accumulation array.
hold on; % Show all profiles at the same time.
axes(handles.axesPlot); % Switch current figure back to the
plot.
if p == pStart
sumProfile = alignedArray;
sumNonZeroElements = nonZeroElements;
else
sumProfile = sumProfile + alignedArray;
sumNonZeroElements = sumNonZeroElements + nonZeroElements;
end
% Plot the profile, adding it to all the other profiles in a single
plot.
hold off;
plot(lineProfile, 'r');
hold on;
plot(alignedArray, 'g');
% Put up bar showing where center was.
PlaceVerticalBarOnPlot(handles, valleyCenter, 'r');
% Put up a bar showing where center got repositioned to.
PlaceVerticalBarOnPlot(handles, round(numberOfSamples/2),'g');
end
drawnow;
end
% Get the averages by dividing by the number of profiles we summed.
% meanProfile = sumProfile ./ sumNonZeroElements;
meanProfile = sumProfile /processedSoFar;
hold off;
% msgboxw('Click OK to see the average of the aligned profiles.');
plot(meanProfile, 'color', 'b', 'linewidth', 2);
minValue = min(meanProfile);
maxValue = max(meanProfile);
ylim([minValue maxValue]);
% msgboxw('Click OK to see the angles.');
% plot(angles, 'color', 'r', 'linewidth', 2);
% Initialize to empty (otherwise get an error if we need to bail out
early).
profileArray = meanProfile';
axes(handles.axesImage);
% Plot the outline of all the profiles. This is the bounding curve
of all the endpoints of the
% profile lines that are perpendicular to the curve the user drew.
[polyROIXCoords, polyROIYCoords] =
GetPolyROI(profileArrayEndPoints);
axes(handles.axesImage);
plot(polyROIXCoords, polyROIYCoords, 'r');
% Update the limits on the sliders that allow user to re-position the
slope start and end.
handles = UpdateSliderLimits(handles);
set(handles.txtInfo, 'string', ['Done. Processed '
num2str(processedSoFar) ' profiles.']);
return % AnalyzeSingleImage
> I had your same idea 2 days ago, but I'm not able to implement it in Matlab.
> Can you give me a piece of code to do that, starting from the coordinates of the centerline?
> However I don't have to compute the width of the vessel. I just have to save the set of coordinates of the 2 edges (the left and the right one to the centerline) of the vessel.
> Cheers,
>
> Alfonso
------------------------------------------------------------------------------------------------
Well here it is. It's about 200 lines. There are some functions you
won't need like alignProfiles because it doesn't apply to your
situation (I was trying to go along an edge). Good luck!
% IMPORTANT: The newsreader may break long lines into multiple lines.
% Be sure to join any long lines that got split into multiple single
lines.
% These can be found by the red lines on the left side of your
% text editor, which indicate syntax errors, or else just run the
% code and it will stop at the split lines with an error.
function [polyROIXCoords polyROIYCoords] = AnalyzeSingleImage(handles,
imgOriginal, ROI_HalfWidth)
% Get profileArray from the global workspace.
global profileArray;
global boundaryVerticesXCoordinates;
global boundaryVerticesYCoordinates;
axes(handles.axesImage); % Switch current figure back to image
box.
plot(boundaryVerticesXCoordinates, boundaryVerticesYCoordinates, 'b',
'linewidth', 2);
% Clear old overlays from image.
% ClearLinesFromAxes(handles);
% Make the panel visible.
set(handles.pnlCharts, 'Visible', 'on');
profileSpacing = 1;
pStart = profileSpacing + 1;
pEnd = length(boundaryVerticesXCoordinates);
axes(handles.axesPlot); % Switch current figure back to the plot.
ClearLinesFromAxes();
numberOfPointsToFit = int16(7); % Number of points along the curve to
fit a quadratic to.
middlePoint = int16(ceil(numberOfPointsToFit / 2));
% Make sure we don't get points so close to the ends of the curve
that we can't get our
% regression quadratic fit to them.
if pStart < middlePoint
pStart = middlePoint;
end
if pEnd > length(boundaryVerticesXCoordinates) - middlePoint
pEnd = length(boundaryVerticesXCoordinates) - middlePoint;
end
% Initialize some stuff.
numberOfProfiles = 0;
for p = pStart : profileSpacing : pEnd
numberOfProfiles = numberOfProfiles + 1;
end
angles = zeros(numberOfProfiles,1);
profileArrayEndPoints = zeros(2, numberOfProfiles, 2);
hold off; % Let first profile autoscale the Y axis.
if ~isempty(boundaryVerticesXCoordinates)
% Do this if there has been a curve drawn.
x = zeros(numberOfPointsToFit, 1);
y = zeros(numberOfPointsToFit, 1);
t = zeros(numberOfPointsToFit, 1);
processedSoFar = 0;
for p = pStart : profileSpacing : pEnd
processedSoFar = processedSoFar + 1;
set(handles.txtInfo, 'string', ['Processing profile #'
num2str(processedSoFar) ' of ' num2str(numberOfProfiles)]);
drawnow;
% For every profileSpacing pixels along the curve, determine a
perpendicular line,
% and then get the profile along that line.
% 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;
end
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);
% coefficients = polyfit(x, y, 2); % Fit 2nd order polynomial.
% 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;
else
% 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);
end
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;
% We may need to swap the line depending on which side of the line
it starts on.
% They can start on different sides of the line depending on the
curvature of the line
% in that region. For consistency, we need to have them all start
on the same side of
% the line.
if p == pStart
lastLine.x3 = x3;
lastLine.x4 = x4;
lastLine.y3 = y3;
lastLine.y4 = y4;
end
% Get flipped values if necessary.
[x3 x4 y3 y4] = FlipLineIfNecessary(x3, x4, y3, y4, lastLine);
% Save those endpoints for next time.
lastLine.x3 = x3;
lastLine.x4 = x4;
lastLine.y3 = y3;
lastLine.y4 = y4;
% Plot the perpendicular line over the image.
axes(handles.axesImage); % Switch current figure back to the image.
plot([x3 x4], [y3 y4], 'g');
% Get the profiles along the perpendicular line.
numberOfSamples = round(ROI_HalfWidth * 2);
% Get the profile along the perpendicular line in the original
image.
[xCoords, yCoords, lineProfile, xi,yi] = improfile(imgOriginal, [x3
x4], [y3 y4], numberOfSamples);
% Each individual profile needs to be offset so that the valley
bottom is at zero.
% This is to account for variations in height that may occur along
the valley nadir.
minValue = min(lineProfile);
% Offset so that the nadir is at 0.
lineProfile = lineProfile - minValue;
% Align the array so that the half-way point is at the middle of
the profile array.
[alignedArray delta valleyCenter] = AlignProfile(lineProfile);
% Find out which elements are > 0. Elements which are zero didn't
have any fibers in
% them and we shouldn't include them in the average.
nonZeroElements = (alignedArray > 0);
% Accumulate the non-zero elements of the profile (i.e., those that
have data in them)
% into the accumulation array.
hold on; % Show all profiles at the same time.
axes(handles.axesPlot); % Switch current figure back to the
plot.
if p == pStart
sumProfile = alignedArray;
sumNonZeroElements = nonZeroElements;
else
sumProfile = sumProfile + alignedArray;
sumNonZeroElements = sumNonZeroElements + nonZeroElements;
end
% Plot the profile, adding it to all the other profiles in a single
plot.
hold off;
plot(lineProfile, 'r');
hold on;
plot(alignedArray, 'g');
% Put up bar showing where center was.
PlaceVerticalBarOnPlot(handles, valleyCenter, 'r');
% Put up a bar showing where center got repositioned to.
PlaceVerticalBarOnPlot(handles, round(numberOfSamples/2),'g');
end
drawnow;
end
% Get the averages by dividing by the number of profiles we summed.
% meanProfile = sumProfile ./ sumNonZeroElements;
meanProfile = sumProfile /processedSoFar;
hold off;
% msgboxw('Click OK to see the average of the aligned profiles.');
plot(meanProfile, 'color', 'b', 'linewidth', 2);
minValue = min(meanProfile);
maxValue = max(meanProfile);
ylim([minValue maxValue]);
% msgboxw('Click OK to see the angles.');
% plot(angles, 'color', 'r', 'linewidth', 2);
% Initialize to empty (otherwise get an error if we need to bail out
early).
profileArray = meanProfile';
axes(handles.axesImage);
% Plot the outline of all the profiles. This is the bounding curve
of all the endpoints of the
% profile lines that are perpendicular to the curve the user drew.
[polyROIXCoords, polyROIYCoords] =
GetPolyROI(profileArrayEndPoints);
axes(handles.axesImage);
plot(polyROIXCoords, polyROIYCoords, 'r');
% Update the limits on the sliders that allow user to re-position the
slope start and end.
handles = UpdateSliderLimits(handles);
set(handles.txtInfo, 'string', ['Done. Processed '
num2str(processedSoFar) ' profiles.']);
return % AnalyzeSingleImage