Get the length of an irregular object in a BW or RGB image and insert it into an image for control

I am facing a well known problem that I cannot solve. I have a root image ( http://cl.ly/image/2W3C0a3X0a3Y ). From this picture, I would like to know the length of the longest root (1st problem), part of the large roots and small roots in% (e.g. diameter as orientation, which is the second problem). It is important that I can distinguish between small and large roots, as this is more or less the purpose of the study (some of them compared to different species). The last thing I would like to draw a line along the measured longest root is to check if everything is measured correctly.

For the length of the longest root, I tried using regionprops (), which is not optimal as it assumes an oval as the base shape, if I'm right. However, in fact I really need support:

How can I get the length of the longest root (the starting point should be where the longest root leaves the main root with the largest diameter)? Is it possible to distinguish between small and large roots, and can I get a part of them? (a coin, a round object in the image is a reference) Can I draw properties such as length and diameter?

I learned how to draw centriodes of ovals and stuff, but I just don't understand how to do it with the suggested values.

Hopefully this is not a double post and this question does not exist as elsewhere, if so, I am sorry about that.

I would like to thank the people on this forum, you did a great job and anyone with a question might be lucky to have you here.

Thanks for the help, Phillip

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% %%%% EDIT

I followed the suggested solution, the code is the following so far:

clc
clear all
close all

img=imread('root_test.jpg');

labTransformation = makecform('srgb2lab');
labI = applycform(img,labTransformation);

%seperate l,a,b
l = labI(:,:,1);
a = labI(:,:,2);
b = labI(:,:,3);

level = graythresh(l);
bw = im2bw(l);
bw = ~bw;
bw = bwareaopen(bw, 200);
se = strel('disk', 5);
bw2=imdilate(bw, se);
bw2 = imfill(bw2, 'holes');
bw3 =bwmorph(bw2, 'thin', 5);
bw3=double(bw3);
I4 = bwmorph(bw3, 'skel', 200);
%se = strel('disk', 10);%this step is for better visibility of the line
%bw4=imdilate(I4, se);
D = bwdist(I4);

      

This brings me to the skeleton painting - that's a lot of progress, thanks for that! I am a little frustrated at the point where I have to calculate the distances. How can I explain to MatLab that it should calculate the distance from all small roots to the main root (how to determine this?)? To do this, I first need to work with diameters, right?

Could you please give one or the other more hint on how to solve the distance / length issue?

Thank you for your help!

Phillip

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% EDIT2

Ok, I managed to separate the individual root parts. This is not what your changes suggested, but at least something. I also have the total length of all the roots - not so bad. But even with (I suppose) a super easy step-by-step explanation, I've never seen such a tree. I stopped at the point at which I have to select an invisible point - the rest is too advanced for me. I don't want to waste any more time and I am very grateful for the help you have already given me. But I guess I'm too MatLab-dumb to do this :) Thanks! Continue like this, it's really helpful.

Phillip

+3


source to share


1 answer


For a starting point, I don't see the need for 3439x2439 resolution for this image, it doesn't seem to add anything important to the problem, so I just worked with a modified 800x567 version (although there should be (almost) no problem to answer for a larger version). Also, you mention regionprops

, but I haven't seen a description of how you got your binary image, so let's start from the beginning.

I examined your image in LAB color space, then binarized the Otsu L-channel, applied an enhancement to that result, assuming the foreground was black (you can do the same by applying erosion instead), and finally removed the small components. The L channel gives a better representation of your image than the more direct luminance formula, resulting in easier segmentation. Dilatation (or erosion) is done in order to join secondary functions, as there are quite a few ramifications that seem irrelevant. This created the following image:

enter image description here

At this point, we might try to use distance transform in combination with grayscale binding (see Soyle's book on morphology and / or "Independent homotopy ordering for binary and seronic anchored skeletons" by Ranwez and Soille). But since this is not easy later, I will consider something simpler here. If we fill the hole in the image above and then thin and trim, we get a rough sketch of the connections between many roots. The following image shows the result of this step, compiled using the original image (and expanded for better rendering):

enter image description here

As expected, the thinned image takes on "shortcuts" due to the filling of the hole. But if such a step had not been taken, we would have ended up loops in this image - something I want to avoid here. However, it seems to provide a decent approximation to the size of the actual roots.

Now we need to calculate the sizes of the branches (or roots). First of all, you need to decide where the main root is. This can be done using the above binary image before expanding and given the distance conversion, but it won't be done here - my interest is only showing the possibility of calculating these lengths. Suppose you know where your main root is, we need to find a path from a given root to it, and then the size of that path is the size of that root. Note that if we remove the branch points from the sparse image, we get a nice set of related components:

enter image description here



Assuming each endpoint is the end of a root, the size of the root is the shortest path to the root root, and the path consists of a set of connected components in the image just depicted. Now you can find the largest, the second largest, and all the others that can be calculated using this process.

EDIT:

To make the last step clear, first let's tag all found branches (open the image in a new tab for better visualization):

enter image description here

Now the "digital" length of each branch is simply the number of pixels in the component. You can later convert this value to "real" length by viewing the object added to the image. Note that at this stage you don't have to depend on image processing algorithms at all, we can build a tree from this view and work there. The tree is constructed as follows: 1) find a branch point in the skeleton that belongs to the main root (this is the "invisible point" between labels 15, 16 and 17 in the above image); 2) create an edge from this point to each branch associated with it; 3) assign weights to the edge according to the number of pixels needed to move to the start of another branch; 4) repeat with new starting branches. For example, at the starting point, it occupies 0 pixels,to reach the start of branches 15, 16 and 17. Then, to reach from the beginning of branch 15 to the end, it takes the size (number of pixels) of branch 15. At this point, we have nothing else to visit along the way, so we create a leaf node. The same process is repeated for all other branches. For example, here is the complete tree for this labeling (double representation of the following tree is much more economical):

enter image description here

You will now find the longest weighted path - which matches the size of the largest root - and so on.

+7


source







All Articles