find diameter based on the centreline and edge

Hi,
I need to find the diameter of the artery model by knowing the centreline and the edges of the artery as:
The black area shows the artery and the white line shows its centreline. I need to calculate the diameter of model at different locations.
Any helps on how to approach it is appreciated.
Thanks
Navid

 Akzeptierte Antwort

Image Analyst
Image Analyst am 23 Okt. 2023

1 Stimme

Compute the Euclidean Distance Transform using bwdist and the skeleton using bwskel then multiply those two images together. Full demo attached.

10 Kommentare

NaviD
NaviD am 21 Feb. 2024
Just a follow up question. I am applying this code to similar images and for some I got too much noise in the diameter width vector. For example, for one case I got this:
and when I plot the width vector, it looks like:
The vertical axis is pixel count.
Any thoughts on I can reduce the noise in the width vector (specifcally between horizontal asix of about 300 to 400, for example)?
Thanks
Navid
Use more resolution. Your blob is only a few pixels wide so of course the width may vary a lot as it twists and turns with only a 1 or 2 pixel wide path.
NaviD
NaviD am 21 Feb. 2024
Unfortunately, I cannot increase the image resolution. Even when there is not much twists and turns, these variations in width happen as well. The variation is quite significant. Any thoughts on how to improve it? Maybe as a post process and a tweak in the code?
Thanks
Navid
Why is it a problem? And what are you calling noise? The noise due to variation in the width vector? Why do you think the width measurements are noise instead of an accurate measurement of the width?
Or are you calling noise the noise in your image that is the cause of the varying widths?
NaviD
NaviD am 23 Feb. 2024
Here is another example,, which doesn't have much twist/turn:
I am refering to the red-dashed area. My understand on how the code calcualte the width (diameter) is that it calcaultes the distance from the centreline (white line on the left figure) to the edges of the artery at different locations across the artery. My question is about these variations highlighted in the dashed area. The variation is not a single pixel or two. In a very short distance, it varied about 10 pixels. I undersntad that it could vary a pixel or two similar to other sections due to the resolution of the image, however, I am concered about the highlighted sections which occur for some of the other images as well,as I need to have accurate measurement of the artery diameter at different locations across the artery.
DGM
DGM am 27 Feb. 2024
Bearbeitet: DGM am 27 Feb. 2024
The problem here is that the variable "widths" is not ordered as you might expect. It's just the set of all pixels along the ridgeline of the distance map. The values are read out of diameterImage columnwise, so anywhere that the curve becomes vertical, it's going to be sampling from different parts of the curve.
% widths is not ordered corresponding to the curve progression
% it's just read out columnwise from the 2D image.
% this shows where widths samples from by plotting the line over the image
[y x] = find(skelImage);
imshow(diameterImage, []); hold on
plot(x,y)
That's fine for finding the mean or other statistics that don't depend on order, but if you want to show the width over the length of the curve, it needs to be ordered.
% instead, get the skeleton coordinates as an ordered set of points
skelpts = bwboundaries(skelImage);
% show that the ordered points progress along the curve as expected
figure
imshow(diameterImage, []); hold on
plot(skelpts{1}(:,2),skelpts{1}(:,1))
% sample from diameterImage along that path
sz = size(diameterImage,1:2);
idx = sub2ind(sz,skelpts{1}(:,1),skelpts{1}(:,2));
idx = idx(1:ceil(end/2)); % the curve gets traced twice, so ignore half
widths = diameterImage(idx);
figure
plot(widths)
The rest of that jitter is just due to the image resolution.
NaviD
NaviD am 27 Feb. 2024
That's great. It is exactly what I was looking for. Thanks.
One very last question:
I need to calculate the length of the centreline (red curve) and I use this code:
n = numel(skelpts{1}(:,2));
length = 0.0;
for i = 1:n-1
length = (length + sqrt( (skelpts{1}(i+1,2)-skelpts{1}(i,2))^2 + (skelpts{1}(i+1,1)-skelpts{1}(i,1))^2 ));
end
However, it seems that the length calculated with this code is much larger that what it should be. Am I missing something?
Thanks
Navid
I think @DGM figured it out. You didn't give your code for getting the width as a function of distance along the skeleton, and I didn't do that in my demo. Not exactly sure how you computed width but if you did what he said, that would explain it.
Total Length depends on how you define it :
  1. if you consider the length just the sum of the skeleton pixels, or
  2. if you want to use the Pythagorean theorem.
So, for two pixels on a diagonal, is that a length of two, or a length of sqrt(2) (going from center of one pixel to the center of the other pixel). If using Pythagorean theorem (case 2), you need a loop. Otherwise (case 1) just sum the pixels.
NaviD
NaviD am 28 Feb. 2024
Verschoben: Image Analyst am 28 Feb. 2024
Thanks both. The width issue has been resolved. Just followed the steps @DGM suggested.
Regarding the length: yes, Iam trying to use the Pythagorean theorem. The issue that I have, when there is a curve/twist in the model, the length calcualted using the code I shared previously, gave me incorrect results. I tried to sort them both in x and y directions, but doesn't help.
These two are how they look like when I sort them out in vertical and horizontal directions. None of them give the correct length, as a portion of path is not sorted.
Any thought on how to solve this issue?
Thanks
Navid
I don't know why the skeleton should give a "solid" patch. Be aware that bwboundaries is meant to give the perimeter of the blob and I'm not sure what the coordinates would be in the degenerate case of a single pixel wide line - not sure if the coordinates are doubled as it traces around the line. You have to make sure that the boundary starts at the ENDPOINT of the skeleton. bwboundaries starts at the left most point of the blob which quite likely is not the same location at the endpoint. You might have to use bwtraceboundary where you can tell it where to start tracing at and use bwmorph to find the endpoints of the skeleton and start there.
But again, you're only giving small snippets of code. I have neither the Crystal Ball Toolbox nor the Mind Reading Toolbox.
If you have any more questions, then attach your image and code to process it in with the paperclip icon after you read this:
Or:

Melden Sie sich an, um zu kommentieren.

Weitere Antworten (0)

Kategorien

Mehr zu Images finden Sie in Hilfe-Center und File Exchange

Community Treasure Hunt

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

Start Hunting!

Translated by