ImageAnalyst <imageanalyst@mailinator.com> wrote in message <02ea58ed-9ce6-4863-80fe-8214281ed4d6@f37g2000yqc.googlegroups.com>...
> 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
>
Thank you, I will try immediately to use it.
Alfonso
> 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
>
Thank you, I will try immediately to use it.
Alfonso