I have a binary image that has two connected components. Both are fairly horizontal and one is on the top of the image and the other at the bottom. What I need to do is to extract only the top component which I want to do (or at least what I think is a good method) by taking the component with the lowest y value for the centroid (because MATLAB uses Java to show images, so the origin is at the top left) and erasing the other component. So far I've been able to use regionprops to find which region has the lowest y value for the centroid, but from there I'm not sure how to get a binary image back again with the component I want.
I've read in the documentation that bwconncomp, labelmatrix, and ismember are useful, but I'm not very sure how to use them well (or at all very much).
This is the solution I just made up, but if there's a better or more elegant one I'd love to know about it!
P.S. filtered is my image
connComp = bwconncomp(filtered);
props = regionprops(filtered, 'Centroid');
justTop = zeros(size(filtered,1), size(filtered,2));
if props(1).Centroid(2) > props(2).Centroid(2)
justTop(connComp.PixelIdxList{2}) = 1;
else
justTop(connComp.PixelIdxList{1}) = 1;
end`
Related
I have found a couple areas referring to filling of gaps in binary images in matlab, however I am still struggling. I have written the following code but I cannot get it to work. Here is my binary image:
.
However, what I'm trying to achieve is the following
.
Does anyone know how to do this? I have been trying using imfill but I know I think I need to define boundaries also with the bwlabel function but I dont know how. Any help would be greatly appreciated.
%%Blade_Image_Processing
clc;
clear;
%%Video file information
obj = VideoReader('T9_720p;60p_60mm_f4.MOV');
% Sampling rate - Frames per second
fps = get(obj, 'FrameRate');
dt = 1/fps;
% ----- find image info -----
file_info = get(obj);
image_width = file_info.Width;
image_height = file_info.Height;
% Desired image size
x_range = 1:image_height;
y_range = 1:image_width;
szx = length(x_range);
szy = length(y_range);
%%Get grayscale image
grayscaleimg1 = rgb2gray(read(obj,36));
grayscaleimg = imadjust(grayscaleimg1);
diff_im = medfilt2(grayscaleimg, [3 3]);
t1=60;
t2=170;
range=(diff_im > t1 & diff_im <= t2);
diff_im (range)=255;
diff_im (~range)=0;
% Remove all those pixels less than 300px
diff_im = bwareaopen(diff_im,2000);
%imshow(diff_im)
%imhist(grayscaleimg)
%Fill gaps in binary image
BW2 = imfill(diff_im,'holes');
There are two main problems: desired object has no readily usable distinguishing features, and it touches other object. Second problem could be perhaps cleared with morphological opening/closing (touching object is thin, desired object not, is this always the case?), but first problem remains. If your object touched edge but others didn't or vice versa, you could do something with imfill and subtractions. As it is now, MAYBE something like this would work:
With opening/closing remove connection, so your object is disjoint.
With imfill, remove what is left of this thin horizontal thing.
Then, you can bwlabel and remove everything that touches sides or bottom of the image - in shown case that would leave only your object.
Exact solution depends heavily on what additional constrains are there for your pictures. I believe it is not a one-shot, rather you have more of those pictures and want to correctly find objects on all? You have to check what holds for all pictures, such as if object always touches only something thin or if it always touches only upper edge etc.
I've been working on an image segmentation problem and can't seem to get a good idea for my most recent problem.
This is what I have at the moment:
Click here for image. (This is only a generic example.)
Is there a robust algorithm that can automatically discard the right square as not belonging to the group of the other four squares (that I know should always be stacked more or less on top of each other) ?
It can sometimes be the case, that one of the stacked boxes is not found, so there's a gap or that the bogus box is on the left side.
Your input is greatly appreciated.
If you have a way of producing BW images like your example:
s = regionprops(BW, 'centroid');
centroids = cat(1, s.Centroid);
xpos = centroids(:,1); should then be the x-positions of the boxes.
From here you have multiple ways to go, depending on whether you always have just one separated box and one set of grouped boxes or not. For the "one bogus box far away, rest closely grouped" case (away from Matlab, so this is unchecked) you could even do something as simple as:
d = abs(xpos-median(xpos));
bogusbox = centroids(d==max(d),:);
imshow(BW);
hold on;
plot(bogusbox(1),bogusbox(2),'r*');
Making something that's robust for your actual use case which I am assuming doesn't consist of neat boxes is another matter; as suggested in comments, you need some idea of how close together the positioning of your good boxes is, and how separate the bogus box(es) will be.
For example, you could use other regionprops measurements such as 'BoundingBox' or 'Extrema' and define some sort of measurement of how much the boxes overlap in x relative to each other, then group using that (this could be made to work even if you have multiple stacks in an image).
I face a well known problem which I am not able to solve.
I have the picture of a root (http://cl.ly/image/2W3C0a3X0a3Y). From this picture, I would like to know the length of the longest root (1st problem), the portion of the big roots and the small roots in % (say the diameter as an orientation which is the second problem). It is important that I can distinguish between fine and big roots since this is more or less the aim of the study (portion of them compared between different species). The last thing, I would like to draw a line along the measured longest root to check if everything was measured right.
For the length of the longest root, I tried to use regionprops(), which is not optimal since this assumes an oval as basic shape if I got this right.
However, the things I could really need support with are in fact:
How can I get the length of the longest root (start point should be the place where the longest root leaves the main root with the biggest diameter)?
Is it possible to distinguish between fine and big roots and can I get the portion of them? (the coin, the round object in the image is the reference)
Can I draw properties like length and diameter into the picture?
I found out how to draw the centriods of ovals and stuff, but I just dont understand how to do it with the proposed values.
I hope this is no double post and this question does not exists like this somewhere else, if yes, I am sorry for that.
I would like to thank the people on this forum, you do a great job and everybody with a question can be lucky to have you here.
Thank you for the help,
Phillip
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
EDIT
I followed the proposed solution, the code until now is as followed:
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 leads my in the skeleton picture - which is a great progress, thank you for that!!!
I am a little bit out at the point where I have to calculate the distances. How can I explain MatLab that it has to calculate the distance from all the small roots to the main root (how to define this?)? For this I have to work with the diameters first, right?
Could you maybe give the one or the other hint more how to accomplish the distance/length problem?
Thank you for the great help till here!
Phillip
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
EDIT2
Ok, I managed to separate the single root parts. This is not what your edit proposed, but at least something. I have the summed length of all roots as well - not too bad. But even with the (I assume) super easy step by step explanation I have 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 dont want to waste more of the time and I am very thankful for the help you gave me already. But I suppose I am too MatLab-stupid to accomplish this :)
Thanks! Keep going like this, it is really helpful.
Phillip
For a pre-starting point, I don't see the need for a resolution of 3439x2439 for that image, it doesn't seem to add anything important to the problem, so I simply worked with a resized version of 800x567 (although there should be (nearly) no problem to apply this answer to the larger version). Also, you mention regionprops but I didn't see any description of how you got your binary image, so let us start from the beginning.
I considered your image in the LAB colorspace, then binarized the L channel by Otsu, applied a dilation on this result considering the foreground as black (the same could be done by applying an erosion instead), and finally removed small components. The L channel gives a better representation of your image than the more direct luma formula, leading to an easier segmentation. The dilation (or erosion) is done to join minor features, since there are quite a bit of ramifications that appear to be irrelevant. This produced the following image:
At this point we could attempt using the distance transform combined with grey tone anchored skeleton (see Soille's book on morphology, and/or "Order Independent Homotopic Thinning for Binary and Grey Tone Anchored Skeletons" by Ranwez and Soille). But, since the later is not easily available I will consider something simpler here. If we perform hole filling in the image above followed by thinning and pruning, we get a rough sketch of the connections between the many roots. The following image shows the result of this step composed with the original image (and dilated for better visualization):
As expected, the thinned image takes "shortcuts" due to the hole filling. But, if such step wasn't performed, then we would end up with cycles in this image -- something I want to avoid here. Nevertheless, 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). The first thing is deciding where the main root is. This can be done by using the above binary image before the dilation and considering the distance transform, but this will not be done here -- my interest is only showing the feasibility of calculating those lengths. Supposing you know where your main root is, we need to find a path from a given root to it, and then the size of this path is the size of this root. Observe that if we eliminate the branch points from the thinned image, we get a nice set of connected components:
Assuming each end point is the end of a root, then the size of a root is the shortest path to the main root, and the path is composed by a set of connected components in the just shown image. Now you can find the largest one, the second largest, and all the others that can be calculated by this process.
EDIT:
In order to make the last step clear, first let us label all the branches found (open the image in a new tab for better visualization):
Now, the "digital" length of each branch is simply the amount of pixels in the component. You can later translate this value to a "real-world" length by considering the object added to the image. Note that at this point there is no need to depend on Image Processing algorithms at all, we can construct a tree from this representation and work there. The tree is built in the following manner: 1) find the branching point in the skeleton that belongs to the main root (this is the "invisible point" between the labels 15, 16, and 17 in the above image); 2) create an edge from that point to each branch connected to it; 3) assign a weight to the edge according to the amount of pixels needed to travel till the start of the other branch; 4) repeat with the new starting branches. For instance, at the initial point, it takes 0 pixels to reach the beginning of the branches 15, 16, and 17. Then, to reach from the beginning of the branch 15 till its end, it takes the size (number of pixels) of the branch 15. At this point we have nothing else to visit in this path, so we create a leaf node. The same process is repeated for all the other branches. For instance, here is the complete tree for this labeling (the dual representation of the following tree is much more space-efficient):
Now you find the largest weighted path -- which corresponds to the size of the largest root -- and so on.
I've got a question regarding the following scenario.
As I post-process an image, I gained a contour, which is unfortunately twice connected as you can see at the bottom line. To make it obvious what I want is just the outter line.
Therefore I zoomed in and marked the line, i want of the large image.
What I want from this selection is only the outter part, which I've marked as green in the next picture. Sorry for my bad drawing skills. ;)
I am using MatLab with the IPT. So I also tried to make out with bwmorph and the hbreak option, but it threw an error.
How do I solve that problem?
If you were successful could you please tell me a bit more about it?
Thank you in advance!
Sincerely
It seems your input image is a bit different than the one you posted, since I couldn't directly collect the branch points (there were too many of them). So, to start handling your problem I considering a thinning followed by branch point detection. I also dilate them and remove from the thinned image, this guarantees that in fact there is no connection (4 or 8) between the different segments in the initial image.
f = im2bw(imread('http://i.imgur.com/yeFyF.png'), 0);
g = bwmorph(f, 'thin', 'Inf');
h = g & ~bwmorph(bwmorph(g, 'branchpoints'), 'dilate');
Since h holds disconnected segments, the following operation collects the end points of all the segments:
u = bwmorph(h, 'endpoints');
Now to actually solve your problem I did some quick analysis on what you want to discard. Consider two distinct segments, a and b, in h. We say a and b overlap if the end points of one is contained in the other. By contained I simply mean if the starting x point of one is smaller or equal to the other, and the ending x point is greater or equal too. In your case, the "mountain" overlaps with the segment that you wish to remove. To determine each of them you remove, consider their area. But, since these are segments, area is a meaningless term. To handle that, I connected the end points of a segment, and used as area simply the interior points. As you can clearly notice, the area of the overlapped segment at bottom is very small, so we say it is basically a line and discard it while keeping the "mountain" segment. To do this step the image u is of fundamental importance, since with it you have a clear indication of where to start and stop tracking a contour. If you used the image has is , you would have trouble determining where to start and stop collecting the points of a contour (i.e., the raster order would give you incorrect overlapping indication).
To reconstruct the segment as a single one (currently you have three of them), consider the points you discarded from g in h, and use those that doesn't belong to the now removed bottom segment.
I'd also use bwmorph
%# find the branch point
branchImg = bwmorph(img,'branchpoints');
%# grow the pixel to 3x3
branchImg = imdilate(branchImg,ones(3));
%# hide the branch point
noBranchImg = img & ~branchImg;
%# label the three lines
lblImg = bwlabel(noBranchImg);
%# in the original image, mask label #3
%# note that it may not always be #3 that you want to mask
finalImg = img;
finalImg(lblImg==3) = 0;
%# show the result
imshow(finalImg)
I have an image containing several specific objects. I would like to detect the positions of those objects in this image. To do that I have some model images containing the objects I would like to detect. These images are well cropped around the object instance I want to detect.
Here is an example:
In this big image,
I would like to detect the object represented in this model image:
Since you originally posted this as a 'gimme-da-codez' question, showing absolutely no effort, I'm not going to give you the code. I will describe the approach in general terms, with hints along the way and it's up to you to figure out the exact code to do it.
Firstly, if you have a template, a larger image, and you want to find instances of that template in the image, always think of cross-correlation. The theory is the same whether you're processing 1D signals (called a matched filter in signal processing) or 2D images.
Cross-correlating an image with a known template gives you a peak wherever the template is an exact match. Look up the function normxcorr2 and understand the example in the documentation.
Once you find the peak, you'll have to account for the offset from the actual location in the original image. The offset is related to the fact that cross-correlating an N point signal with an M point signal results in an N + M -1 point output. This should be clear once you read up on cross-correlation, but you should also look at the example in the doc I mentioned above to get an idea.
Once you do these two, then the rest is trivial and just involves cosmetic dressing up of your result. Here's my result after detecting the object following the above.
Here's a few code hints to get you going. Fill in the rest wherever I have ...
%#read & convert the image
imgCol = imread('http://i.stack.imgur.com/tbnV9.jpg');
imgGray = rgb2gray(img);
obj = rgb2gray(imread('http://i.stack.imgur.com/GkYii.jpg'));
%# cross-correlate and find the offset
corr = normxcorr2(...);
[~,indx] = max(abs(corr(:))); %# Modify for multiple instances (generalize)
[yPeak, xPeak] = ind2sub(...);
corrOffset = [yPeak - ..., xPeak - ...];
%# create a mask
mask = zeros(size(...));
mask(...) = 1;
mask = imdilate(mask,ones(size(...)));
%# plot the above result
h1 = imshow(imgGray);
set(h1,'AlphaData',0.4)
hold on
h2 = imshow(imgCol);
set(h2,'AlphaData',mask)
Here is the answer that I was about to post when the question was closed. I guess it's similar to yoda's answer.
You can try to use normalized cross corelation:
im=rgb2gray(imread('di-5Y01.jpg'));
imObj=rgb2gray(imread('di-FNMJ.jpg'));
score = normxcorr2(imObj,im);
imagesc(score)
The result is: (As you can see, the whitest point corresponds to the position of your object.)
The Mathworks has a classic demo of image registration using the same technique as in #yoda's answer:
Registering an Image Using Normalized Cross-Correlation