How to create a silhouette from image

19 views (last 30 days)
I need to create a silhouette from an image to take the central moments on for a car classifier. I've already been able to process the image using k-means clustering, but can't get the last part of my problem solved. I basically need to remove the largest region that touches all four borders of the image, then make the rest black (leaving a white background). Below are how far I've gotten to my goal. How can I go from the second image to what i'm looking for?

Accepted Answer

Image Analyst
Image Analyst on 24 Feb 2017
Try this. You'll see you get a black silhouette of the car (including the shadow since your kmeans did not classify it as part of the background, but as part of the car which is why I didn't recommend kmeans):
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 = 15;
%===============================================================================
% Get the name of the image the user wants to use.
baseFileName = 'Full image k=3.bmp';
% Get the full filename, with path prepended.
folder = pwd
fullFileName = fullfile(folder, baseFileName);
%===============================================================================
% Read in demo image.
indexedImage = imread(fullFileName);
% Get the dimensions of the image.
[rows, columns, numberOfColorChannels] = size(indexedImage);
% Display the original image.
subplot(2, 2, 1);
imshow(indexedImage, []);
axis on;
caption = sprintf('Original kmeans Indexed Image, %s', baseFileName);
title(caption, '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;
hp = impixelinfo(); % Set up status line to see values when you mouse over the image.
% Get a mask for the value of the pixels in the upper left corner at pixel 2,2
% Because there seems to be a 1 pixel wide edge effect so we're going in one pixel.
mask = indexedImage == indexedImage(2, 2);
% Display the image.
subplot(2, 2, 2);
imshow(mask, []);
axis on;
caption = sprintf('Initial Mask Image');
title(caption, 'FontSize', fontSize, 'Interpreter', 'None');
drawnow;
% Get largest region, which will be the background..
mask = bwareafilt(mask, 1);
% Fill holes.
mask = ~bwareafilt(~mask, 1);
% Display the image.
subplot(2, 2, 3);
imshow(mask, []);
axis on;
caption = sprintf('Silhouette Image');
title(caption, 'FontSize', fontSize, 'Interpreter', 'None');
drawnow;
  2 Comments
Image Analyst
Image Analyst on 24 Feb 2017
So basically 3 lines of code:
mask = indexedImage == indexedImage(2, 2);
mask = bwareafilt(mask, 1);
mask = ~bwareafilt(~mask, 1);
get you what you asked for, doesn't it? You could even get that down to one line of code if you wanted:
mask = ~bwareafilt(~bwareafilt(indexedImage == indexedImage(2, 2), 1), 1);
but that's a bit cryptic and hard to follow.
If you want the silhouette white instead of black, get rid of the ~ before bwareafilt() on the last line:
mask = indexedImage == indexedImage(2, 2);
mask = bwareafilt(mask, 1);
mask = bwareafilt(~mask, 1);
Brenton Poke
Brenton Poke on 27 Feb 2017
Edited: Brenton Poke on 27 Feb 2017
That works beautifully with my current code, thanks! This was my result.

Sign in to comment.

More Answers (4)

Image Analyst
Image Analyst on 23 Feb 2017
You don't need kmeans. It's not needed for an image like that. Just wastes time for no reason. Simply find a mask and you're done
topGL = 255; % Whatever white is.
silhouetteImage = rgbImage(:,:,1) < topGL | rgbImage(:,:,2) < topGL | rgbImage(:,:,3) < topGL;
imshow(silhouetteImage); % Display logical/binary image.
  2 Comments
Brenton Poke
Brenton Poke on 23 Feb 2017
I'm not sure how to apply your code or what it means. I used the k-means method because that's what I learned in a course and much of the code for it was done for us. I'm really close and just want to work off of what I already have done.
Image Analyst
Image Analyst on 23 Feb 2017
I'm just making a mask of everything that is not pure white. If you want to do it the more complicated way using kmeans(), then you need to take your kmeans image and extract the class that is the background, and use bwareafilt() (because there are more purple regions there than just the surround).
% kmeans code..... like attached demo.... then...
backgroundClass = kmeansImage == 1; % Or whatever index it is.
silhouetteImage = bwareafilt(backgroundClass, 1); % Extract largest region.
imshow(silhouetteImage); % Display logical/binary image.

Sign in to comment.


John BG
John BG on 23 Feb 2017
Hi Brenton
please help me out and tell if I am on the right direction
1.
capture
A=imread('etiquette.jpg');
% figure(1);imshow(A);
2. picking on peculiar combination of car colour
A(A<80)=255;
figure(2);imshow(A)
A1=A(:,:,1);A2=A(:,:,2);A3=A(:,:,3);
p1=find(A1>200);
p2=find(A2<170);
pc=intersect(p1,p2);
B=zeros(size(A1));
B(pc)=255;
figure(3);imshow(B)
.
would the chassis do as point for, from here, get the silhouette?
there is a bit of noise and reflection ribbon, you may also want it off, right?
awaiting answer
John BG
  6 Comments
Image Analyst
Image Analyst on 24 Feb 2017
Did you see my second answer (below)? It does what you want in 3 lines of code.
John BG
John BG on 24 Feb 2017
Brenton
because you told me to start from the image you obtained with your K-means analysis I started from im2.jpg here attached.
The size may not match because I took the image from your question.
Apply my lines to the outcome of your K-means, check it works with im2.jpg here attached.
John BG

Sign in to comment.


Shiba Kuanar
Shiba Kuanar on 11 Oct 2019
Hi All,
I used the code - to get a black silhouette of the car (very beginning)
I am getting the result but with some error message (below): (also attached figure for review)
__________________________________________________________________
Error using images.internal.imageDisplayValidateParams>validateCData (line 119)
If input is logical (binary), it must be two-dimensional.
Error in images.internal.imageDisplayValidateParams (line 27)
common_args.CData = validateCData(common_args.CData,image_type);
Error in images.internal.imageDisplayParseInputs (line 78)
common_args = images.internal.imageDisplayValidateParams(common_args);
Error in imshow (line 241)
images.internal.imageDisplayParseInputs({'Parent','Border','Reduce'},preparsed_varargin{:});
Error in SilhouetShiba (line 44)
imshow(mask, []);
  1 Comment
Image Analyst
Image Analyst on 11 Oct 2019
TestImageSIL.png is probably not a grayscale image. Use rgb2rgray() to make in into grayscale.

Sign in to comment.


Shiba Kuanar
Shiba Kuanar on 11 Oct 2019
Thank You

Community Treasure Hunt

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

Start Hunting!