Help in measuring diameter of vessel

13 views (last 30 days)
Hello,
I need help in understanding why my code doesn't output quite what I thought it would. I am trying to measure the diameter of a vessel in a 512x512 image by measuring the diameter at several points and averaging the measurements. Here is my code
segmentLength = round(size(image,1)/segments);
[rightrow, rightcol] = find(image==3);
rightwall = [rightcol rightrow];
for j = 1:segmentLength:(size(image,1)-segmentLength)
midpt = j+round(segmentLength/2);
[~, midptcol] = find(image(midpt,:)==2);
if isempty(midptcol)==0
[d, p] = min((rightwall(:,1)-midptcol).^2+(rightwall(:,2)-midpt).^2);
%p is the row index of rightwall containing the nearest point
d = sqrt(d);
diameter = [diameter d];
end
end
I changed the value along the right side of the vessel to be 3 in order to identify what wall is the wall on the right and used 20 for my value of segments. When I graph the points to see what this code has done, the points with shortest distance don't seem to actually be those points (as far as I can tell with my eye) and so are not quite the diameter at that point. Can you help me understand what I am missing? Here is the image where the points on the right don't match up with where I would expect them to:
Thanks! Michael

Accepted Answer

Image Analyst
Image Analyst on 15 Mar 2016
Edited: Image Analyst on 4 Sep 2021
Michael, try this:
clc; % Clear the command window.
close all; % Close all figures (except those of imtool.)
clear; % Erase all existing variables. Or clearvars if you want.
workspace; % Make sure the workspace panel is showing.
format long g;
format compact;
fontSize = 20;
% Read in mat file.
storedStructure = load('binaryimage.mat');
binaryImage = storedStructure.BWfinal;
% Display the image.
subplot(2, 2, 1);
imshow(binaryImage, []);
title('Original Binary Image', 'FontSize', fontSize, 'Interpreter', 'None');
% Set up figure properties:
% Enlarge figure to full screen.
set(gcf, 'Units', 'Normalized', 'OuterPosition', [0 0 1 1]);
% Get rid of tool bar and pulldown menus that are along top of figure.
set(gcf, 'Toolbar', 'none', 'Menu', 'none');
% Give a name to the title bar.
set(gcf, 'Name', 'Demo by ImageAnalyst', 'NumberTitle', 'Off')
drawnow;
% Fill the image.
binaryImage(1,:) = true;
binaryImage(end,:) = true;
binaryImage = imfill(binaryImage, 'holes');
% Display the image.
subplot(2, 2, 2);
imshow(binaryImage, []);
title('Original Binary Image', 'FontSize', fontSize, 'Interpreter', 'None');
drawnow;
% Get the Euclidean Distance Transform.
binaryImage(1,:) = false;
binaryImage(end,:) = false;
edtImage = bwdist(~binaryImage);
% Display the image.
subplot(2, 2, 3);
imshow(edtImage, []);
title('Distance Transform Image', 'FontSize', fontSize, 'Interpreter', 'None');
drawnow;
skelImage = bwmorph(binaryImage, 'skel', inf);
skelImage = bwmorph(skelImage, 'spur', 40);
% There should be just one now. Let's check
[labeledImage, numLines] = bwlabel(skelImage);
fprintf('Found %d lines\n', numLines);
% Display the image.
subplot(2, 2, 4);
imshow(skelImage, []);
title('Skeleton Image', 'FontSize', fontSize, 'Interpreter', 'None');
% Measure the radius be looking along the skeleton of the distance transform.
meanRadius = mean(edtImage(skelImage))
meanDiameter = 2 * meanRadius
message = sprintf('Mean Radius = %.1f pixels.\nMean Diameter = %.1f pixels',...
meanRadius, meanDiameter);
uiwait(helpdlg(message));
  5 Comments
Sandip Sadhukhan
Sandip Sadhukhan on 5 Sep 2021
Thanks a lot for your quick response.

Sign in to comment.

More Answers (1)

Image Analyst
Image Analyst on 14 Mar 2016
I think the usual way to do this, and more accurate than your way, is to get a binary image of the vessel, then compute the Euclidean Distance Transform with bwdist(), then to skeletonize the binary image and use it to mask the EDT image to get an image with values only along the centerline of the vessel. This gives you all the radii along the axis of the vessel. Then you simply take the mean or histogram or whatever you want.
If you have an image of just the edges then you need to seal the top and bottom edge, then call imfill, then erase the top and bottom rows.
Something like this:
binaryImage(1,:) = true;
binaryImage(end,:) = true;
binaryImage = imfill(binaryImage, 'holes');
binaryImage(1,:) = false;
binaryImage(end,:) = false;
edtImage = bwdist(binaryImage);
skelImage = bwmorph(binaryImage, 'skel', inf);
meanRadius = mean(edtImage(skelImage));
meanDiameter = 2 * meanRadius;
The skeleton will look like a "Y" near the ends of the vessel, so you can get the main spine of the skeleton by using bwmorph() to find the branchpoints and setting those to false and then use bwareafilt(binaryImage, 1) to get the longest branch.
Try it and let me know how it goes. Attach the initial binary image if you get stuck.
  5 Comments
Image Analyst
Image Analyst on 14 Jun 2017
You can post a question on Answers, and if I get time and it doesn't take too much time, I might answer. If it's a major project, I'll probably just refer you to relevant published articles or bibliographies, like this one, or possibly to a university that I know that you could hire to do the work. I usually don't spend more than 5 minutes answering - 30 minutes tops, but that would have to be something that looks really fun, interesting, or challenging, or something I might think would make a nice general purpose demo.
Jyoti Jethe
Jyoti Jethe on 16 Nov 2022
@Image Analyst Hi, I am new to image processing in matlab. Please help to find out the diameter of blood vessel in the given image. There are network of vessels, I tried using skeletonization but still unable to get a proper diameter value and way to plot it (or may be histogram of the value of diameter). Following is the piece of code and the image attached is rerode image:
sktn_img=2*bwdist(~rerode);
%imshow(sktn_img);
skeleton=bwmorph(rerode,'skel',inf);
diameter_img=sktn_img.*double(skeleton);
Please help

Sign in to comment.

Community Treasure Hunt

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

Start Hunting!