Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"Cut out" an image based on edge detection

This is my original image: Weld Nut

I've asked the user to crop it, converted it to grayscale and ran this line of code on it:

edgeImg = edge(grayImg,'canny',0.23);

This is the result:

Edges

I want to "cut out" everything the middle circle and the outside edge, essentially. I'm having a really hard time figuring out how to do this and honestly I'm at a loss.

I considered trying to fill in the area that I want to keep in the binary image, and then I could use it as a stamp, but I couldn't come up with a way that didn't fill in the middle circle as well.

Any ideas?

Thanks.

EDIT: This white area is what I want to keep:

Highlighted

like image 858
TechnoSam Avatar asked Oct 19 '22 13:10

TechnoSam


2 Answers

I would suggest not to do edge detection in the first place, you are loosing valuable information related to color. You may try some clustering algorithm, like K-Means (including source code) or whatever else.

After clustering is done, you may keep pixels that are related to cluster(s) with the object. Desirable cluster(s) may be selected based on the object position in the image (including cropping of the image) and its color.

Code example of K-Means clustering for 2 clusters is below:

he = imread('D:\1.jpg');
imshow(he);

cform = makecform('srgb2lab');
lab_he = applycform(he,cform);

ab = double(lab_he(:,:,2:3));
nrows = size(ab,1);
ncols = size(ab,2);
ab = reshape(ab,nrows*ncols,2);

%One cluster for your object and one for background
nColors = 2;
[cluster_idx, cluster_center] = kmeans(ab,nColors,'distance','sqEuclidean', ...
                                      'Replicates',2);


pixel_labels = reshape(cluster_idx,nrows,ncols);

segmented_images = cell(1,3);
rgb_label = repmat(pixel_labels,[1 1 3]);

for k = 1:nColors
    color = he;
    color(rgb_label ~= k) = 0;
    segmented_images{k} = color;
end

%Show both clusters: object and non-object
imshow(segmented_images{1});
figure;
imshow(segmented_images{2});

The resulting segmentation is quite good:

enter image description hereenter image description here

like image 200
Konstantin Avatar answered Oct 27 '22 08:10

Konstantin


Instead of using K-Means, you can simply use the color thresholder since you have so much color information. Then you can call the mask function automatically generated called createMask and further post process your image there. The code is below. The best part of this method is that createMask is reusable for any image, not just your own!

% Read Image
I = imread('r8ATB.jpg');
figure; imshow( I );

% Crop Image
C = I(75:490,40:460,:);
figure; imshow( C );

% Plot Noisy Mask
[BW,MK] = createMask( C );
figure; imshow( BW );
figure; imshow( BW );

% Fix Holes
imopen( ... );

This is the original image.

Original Image

Cropped Image

enter image description here

Start threshold window.

enter image description here

Threshold Parameters

enter image description here

Created mask

enter image description here

Final Image

enter image description here

The createMask.m function that is automatically generated using my parameter is as follows.

function [BW,maskedRGBImage] = createMask(RGB)
%createMask  Threshold RGB image using auto-generated code from colorThresholder app.
%  [BW,MASKEDRGBIMAGE] = createMask(RGB) thresholds image RGB using
%  auto-generated code from the colorThresholder App. The colorspace and
%  minimum/maximum values for each channel of the colorspace were set in the
%  App and result in a binary mask BW and a composite image maskedRGBImage,
%  which shows the original RGB image values under the mask BW.

% Auto-generated by colorThresholder app on 23-Apr-2015
%------------------------------------------------------


% Convert RGB image to chosen color space
I = rgb2hsv(RGB);

% Define thresholds for channel 1 based on histogram settings
channel1Min = 0.983;
channel1Max = 0.167;

% Define thresholds for channel 2 based on histogram settings
channel2Min = 0.205;
channel2Max = 1.000;

% Define thresholds for channel 3 based on histogram settings
channel3Min = 0.341;
channel3Max = 1.000;

% Create mask based on chosen histogram thresholds
BW = ( (I(:,:,1) >= channel1Min) | (I(:,:,1) <= channel1Max) ) & ...
    (I(:,:,2) >= channel2Min ) & (I(:,:,2) <= channel2Max) & ...
    (I(:,:,3) >= channel3Min ) & (I(:,:,3) <= channel3Max);

% Invert mask
BW = ~BW;

% Initialize output masked image based on input image.
maskedRGBImage = RGB;

% Set background pixels where BW is false to zero.
maskedRGBImage(repmat(~BW,[1 1 3])) = 0;

You can then proceed to use imopen and imclose to clean up your mask. Then apply it to the image. My method requires tuning to get it perfect as per any method, but it will give you consistent results.

To obtain the complement of your image, all you need to do is invert the mask and apply it.

like image 36
krisdestruction Avatar answered Oct 27 '22 09:10

krisdestruction