Image Processing, How can I separate this bird from background?
1 Ansicht (letzte 30 Tage)
Ältere Kommentare anzeigen
I am wondering to separate a bird from background itself, and I have tried some different filters and but its not removing white lines which are not , anybody has an idea!
6 Kommentare
Akzeptierte Antwort
David Young
am 25 Nov. 2011
Here is a description of the way I did it - but note that there are many different possibilities. If you try to do it this way and get stuck, show me what you've written and I'll try to help.
- I read the image into memory using imread, and thresholded it (using the < operator) to give me a true binary image. At the same time I inverted it, so that foreground pixels had the value 1 and background pixels were 0.
- I made the assumption that the bars are parallel to the rows of the image. (Actually this isn't quite true for the first bar.) For any image processing task, identifying the assumptions you can make is a crucial step. To use the assumption, I found the sum of the pixel values in each row of the binary image. Every row where the sum exceeded a threshold (I used 80% of the image width) was identified as being in a bar. This was simply a matter of thresholding the sum vector.
- I made an image of the bars. I started with an array of zeros and set every pixel in the rows in the bars to one.
- I removed the bars from the original binary image, using logical operators. That gave me a bird outline, but with gaps in it where the bars had been.
- I tidied up the bird outline to remove the single-pixel line that resulted from the misalignment of the top bar, using morphological functions imerode and imdilate, and a vertical structuring element. This also removed a few isolated pixels from the bird outline, and for a perfect solution I would spend more time thinking about this step.
- Filling in the gaps was the most complex part. I started by dilating the bird outline using a vertical structuring element, and finding the overlaps between this and the bar image using the & operator. This gave me a set of horizontal lines at the top and bottom edge of the part of each bar that crossed the bird. I deleted lines shorter than 5% of the width of the image, to tidy up the region round the bird's feet.
- I found the end points of the lines, again using morphological operations, and I sorted the points in order of increasing row number.
- I then took the end points in groups of 4 and used roipoly to make a mask for each group. This gave me a binary image of each section of bar where it passed in front of the bird, taking the outline of the bird to be a straight line in those regions where it is obscured by the bar.
- I combined the bar sections and the bird outline using the | operator, to finally give me the bird with the gaps filled in.
EDIT Now that any likely courswork deadline will have passed, here's my code corresponding to the steps above, as a demo for reference.
% 1. read the bird image as downloaded
imraw = imread('tempbird.jpg');
% make it into a proper binary image, foreground 1
im = imraw < max(imraw(:))/2;
imshow(im); pause
% 2. find the bar rows
bar_rows = sum(im, 2) > 0.8 * size(im, 2);
% 3. make a bar image
im_bars = false(size(im));
im_bars(bar_rows, :) = true;
% 4. remove the bars from the image
im_nobars = im & ~im_bars;
imshow(im_nobars); pause
% 5. tidy image by removing 1-pixel thick horizontal structures
im_nobars = imerode(im_nobars, [1; 1]);
im_nobars = imdilate(im_nobars, [1; 1]);
imshow(im_nobars); pause
% 6. dilate bars and get overlap with bird - a set of horizontal lines
bar_bounds = im_bars & imdilate(im_nobars, [1; 1; 1]);
imshow(bar_bounds); pause
% tidy overlap lines by removing small segments
minline = size(im, 2) / 20;
bar_bounds = bwareaopen(bar_bounds, minline);
imshow(bar_bounds); pause
% 7. find end points of overlap lines and sort them
[yleft, xleft] = find(~imerode(bar_bounds, [1 1 0]) & bar_bounds);
[yright, xright] = find(~imerode(bar_bounds, [0 1 1]) & bar_bounds);
[yleft, ind] = sort(yleft);
xleft = xleft(ind);
[yright, ind] = sort(yright);
xright = xright(ind);
% 8. fill in bar regions where bars cross bird
bars_in_bird = false(size(im));
for poly = 1:2:length(xleft)
x = [xleft(poly) xright(poly) xright(poly+1), xleft(poly+1)];
y = [yleft(poly) yright(poly) yright(poly+1), yleft(poly+1)] ...
+ [-0.5 -0.5 0.5 0.5];
bar_part = roipoly(im, x, y);
bars_in_bird = bars_in_bird | bar_part;
end
imshow(bars_in_bird); pause
% 9. combine bird and bars to give final bird outline
bird = ~(im_nobars | bars_in_bird);
imshow(bird);
5 Kommentare
David Young
am 25 Nov. 2011
On the first part of your code:
A = imread('Bird.bmp');
%A = (A<80);
A = double(A);
A = imcomplement(A);
For my approach, I'd have kept the line A = A<80. Then I would not have a call to double (because having A as class logical is good) and I would not need the call to imcomplement.
On your computation of the bar image, you're not too far off if you accept that the first column of the image is sufficient evidence for a bar (I used the sum across columns as I felt it was more robust). However, you have some bugs: you need the line "i=1" to come *after* the line "for j=1:n", because i needs to start from 1 for each column; you don't need the inner loop over j. If you make these changes, you get
[m,n] = size(A);
barimage = zeros(m,n);
for j= 1:n
i = 1;
while i~=m
if A(i,1) == 1
barimage(i,j)=1;
end
i = i+1;
end
end
This works OK (as long as A is a proper binary image).
There are neater ways to do this in MATLAB: for example you could just say
barimage = zeros(size(A));
barimage(A(:,1), :) = 1;
which has the same effect as the loops. Have a look at the documentation on logical indexing to understand this.
Weitere Antworten (0)
Siehe auch
Kategorien
Mehr zu Modify Image Colors finden Sie in Help Center und File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!