Filling region of RGB image specified by polygon in Matlab - matlab

After finding boundaries of my regions of interest in an RGB image I want to fill them with specific color on the original picture
img=imread('I.png');
BW=~im2bw(img,0.5);
B = bwboundaries(a2);
for k = 1:length(B)
boundary = B{k};
% here should color everything inside boundary in blue
end
What function can I use to do this? I tried also using imshow() and than ploting regions on it, but don't know how to save it in the original resolution.

If you insist on filling with polygon, you can use fill, but then you might face some problems:
img = imread('Prueba.jpg');
figure;
imshow(img)
BW = ~im2bw(img, 0.55);
B = bwboundaries(BW);
hold on
for k = 1:length(B)
boundary = B{k};
fill(boundary(:, 2), boundary(:, 1), 'b')
end
As shown in this example, there are regions of the image that are surrounded by a boundary but they are actually supposed to be outside the boundary.
Instead, in this way you can avoid the issue:
imgR = img(:, :, 1);
imgG = img(:, :, 2);
imgB = img(:, :, 3);
imgR(BW) = 0;
imgG(BW) = 0;
imgB(BW) = intmax(class(imgB));
IMG = cat(3, imgR, imgG, imgB);
figure; imshow(IMG)

Related

How can I detect the defect in this image of a semiconductor?

So I have this image of a semiconductor wafer and it has a defect in it which I need to detect using Matlab. I should detect only it and not its background. I need to also measure its perimeter and area.
So far I have this code where I convert the original image to a binary image and then use dilation on it and then try to get its contour. When getting the perimeter and the area, I receive the outcome not only for the defect but for the rest of the image which is not what I want. How can I extract the defect only so I can get only its area and parameter.
The image:
fig3 = imread('figure3.png');
imshow(fig3);
title('Original image', 'FontSize', 18);
%Gray image
fig3Gray = rgb2gray(fig3);
%Binary image
BW3 = imbinarize(fig3Gray,0.5);
imshow(BW3);
title('Binary image', 'FontSize', 18);
se3 = strel('square',5);
%Dilation image
dilated3 = imdilate(BW3,sr);
imshow(dilated3);
title('Dilated image', 'FontSize', 18);
minus3 = ~(BW3-dilated3);
imshow(minus3);
title('Contour image', 'FontSize', 18);
imshowpair(minus3,BW3,'montage');
%Perimeter and Area calculation
Coon3 = bwconncomp(~BW3)
ANS3 = length(Coon3.PixelIdxList{1});
OUTPUT3 = regionprops(Coon3,'Perimeter','Area');
P3 = OUTPUT3.Perimeter
Area3 = OUTPUT3.Area
Let's start by reading the image and converting it to binary. Note that I have lowered the threshold to eliminate unwanted details.
clear; close all; clc
fig3 = imread('XEQ59.png');
imshow(fig3);
title('Original image', 'FontSize', 18);
%Gray image
fig3Gray = rgb2gray(fig3);
%Binary image
BW3 = imbinarize(fig3Gray, 0.2); % lowered threshold
figure; imshow(BW3)
title('binary image')
Now we move on to find the coordinate of the defect. To do this, we define a structuring element that defines our desired shape se.
We are looking for the parts in the image that match with se. For a given coordinate to match, the surrounding area must exactly be se.
Note that gray values here are ignored, they can be either white or black.
se is manually defined where 1 represents white, -1 represents black, and 0 represents ignored pixels.
% hit-miss
se = [1, 1, -1*ones(1,5), ones(1, 3); ...
ones(6,1), -1*ones(6), zeros(6,2), ones(6,1); ...
ones(3,2), zeros(3,1), -1*ones(3,6), ones(3,1)];
figure; imshow(uint8(255/2*(se+1)), 'InitialMagnification', 3000)
title('structuring element')
Applying hit-miss operation to find the position of the defect:
pos = bwhitmiss(BW3, se);
figure; imshow(pos)
title('position of defect')
input('Press enter to continue...')
Now that we have the position, we grow that particular pixel position until it grows no more, in order to obtain defect.
% get the defect
close all; clc
def = pos;
last_def = zeros(size(def));
while ~isequal(def, last_def)
last_def = def;
def = ~BW3 & imdilate(def, ones(3));
imshow(def)
title('defect')
pause(0.1)
end
Calculating the area and the perimeter:
% area
area = sum(def(:))
% perimeter
vert = imdilate(def, [1; 1; 1]) - def;
horz = imdilate(def, [1 1 1]) - def;
perimeter = sum(vert(:)) + sum(horz(:))
area =
102
perimeter =
54
This question is much more difficult then your previous question.
Following solution uses an iterative approach (two iterations).
Includes heuristic about the difference from the cluster to it's neighbors.
Includes a heuristic that the cluster can't be too tall or too long.
Please read the comments:
clear
fig3 = imread('figure3.png');
fig3Gray = rgb2gray(fig3);
fig3Gray = im2double(fig3Gray); %Convert from uint8 to double (MATLAB math works in double).
%figure;imshow(fig3Gray);
%Apply median filter with large radius.
Med = medfilt2(fig3Gray, [51, 51], 'symmetric');
%figure;imshow(Med);
D = abs(fig3Gray - Med);
%figure;imshow(D);impixelinfo
BW = imbinarize(D, 0.3);
%figure;imshow(BW);impixelinfo
Coon = bwconncomp(BW);
fig3GrayMasked = fig3Gray;
%Cover the tall clusters and the long clusters.
for i = 1:length(Coon)
C = Coon.PixelIdxList{i}; %Cluster coordinates.
[Y, X] = ind2sub(size(fig3Gray), C); %Convert to x,y indices.
is_tall = (max(Y) - min(Y)) > 50; %true if cluster is tall.
is_wide = (max(X) - min(X)) > 50; %true if cluster is wide.
%Replace tall and long clusters by pixels from median image.
if ((is_tall) || (is_wide))
fig3GrayMasked(C) = Med(C);
end
end
%figure;imshow(fig3GrayMasked);impixelinfo
%Second iteration: search largest cluster on fig3GrayMasked image.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Med = medfilt2(fig3GrayMasked, [51, 51], 'symmetric');
D = abs(fig3GrayMasked - Med);
%figure;imshow(D);impixelinfo
BW = imbinarize(D, 0.3);
%figure;imshow(BW);impixelinfo
Coon = bwconncomp(BW);
%Find index of largest cluster in list of clusters Coon.PixelIdxList
[~, i] = max(cellfun(#numel, Coon.PixelIdxList));
%Get the indices of the largest cluster
C = Coon.PixelIdxList{i};
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%Paint cluster in yellow color (just for fun).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
BW = zeros(size(BW), 'logical');
BW(C) = 1;
Y = im2uint8(cat(3, ones(size(BW)), ones(size(BW)), zeros(size(BW))));
fig3(cat(3, BW, BW, BW)) = Y(cat(3, BW, BW, BW));
figure;imshow(fig3)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Result:

Create boundary around the object

I have the input image. I want to create the boundary around the object and marked the boundary pixels as gray i.e. 128 intensity value. I need this type of output image. I traced the boundary of the object:
level = graythresh(im);
BW = im2bw(im,level);
figure; imshow(BW);
[B,L] = bwboundaries(BW,'noholes');
imshow(im);
hold on
for k = 1:length(B)
boundary = B{k};
plot(boundary(:,2), boundary(:,1), 'Color', [0.5 0.5 0.5], 'LineWidth', 5)
end
But it will only plot the boundary over the image. I want to create this boundary around the object of input image. How can I do this? I hope my question is clear.
While I don't know why you wan this, a word of advice: you may not want to do it. You are losing information of the image by doing so. It is possible that for you application knowing the indices of the boundaries is enough, and you do already know them.
However, this is what you would need to do in case of really wanting to do it:
clear;
clc;
im=imread('https://i.stack.imgur.com/r7uQz.jpg');
im=im(31:677,90:1118);
level = graythresh(im);
BW = im2bw(im,level);
[B,L] = bwboundaries(BW,'noholes');
for k = 1:length(B)
boundary = B{k};
%%%%%%%%% Fill the boundary locations with he desired value.
for ii=1:size(boundary,1)
im(boundary(ii,1), boundary(ii,2))=128;
end
end
If you want "fat" lines as in your image, add this after:
im128=im==128;
bigboundary=imdilate(im128,ones(5));
im(bigboundary)=128;
You can binarize the image and detect the contours using OpenCV.
Here is the Python implementation:
img = cv2.imread(r'D:\Image\temp1.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret,bw = cv2.threshold(gray,100,255,cv2.THRESH_BINARY)
_,contours,hierarchy = cv2.findContours(bw, cv2.RETR_CCOMP, 1)
for cnt in contours:
c = np.random.randint(0,256,3)
c = (int(c[0]), int(c[1]), int(c[2]))
cv2.drawContours(img,[cnt],0,c,2)
Output image:

Assigning colors to segmented pictures in MATLAB

I was dealing with color segmentation with MATLAB. I used k-means clustering based on this document and come this far codewise;
global imgRGB;
global imgLAB;
img = imgRGB;
cform = makecform('srgb2lab');
imgLAB = applycform(img, cform);
ab = double(imgLAB(:,:,2:3));
rows = size(ab,1)
cols = size(ab,2);
ab = reshape(ab, rows*cols, 2);
cluster = 5;
[idx center] = kmeans(ab, cluster, 'distance', 'sqEuclidean', 'Replicates', 5);
label = reshape(idx, rows, cols);
figure; imshow(label, []);
imgSeg = cell(5);
rgb_label = repmat(pixel_labels, [1 1 3]);
for k=1:cluster
color = img;
color(rgb_label ~= k) = 0;
imgSeg{k} = color;
end
figure;
imshow(imgSeg{1});
I take image as input that is why it is defined global.
For a colored image like the one in link, it produces the grayscale output.
I think it assigns gray tones as colors but I need to assign a color to each cluster. I mean not gray tone but a color. How can I achieve that?
You should use a different colormap for your figure, when displaying the labels directly.
Try:
figure;
imshow(label, []);
colormap( rnad(max(imgSeg{1}(:))+1, 3) ); % use random color map
However, if you wish to convert the pixel_labels to an RGB image (3 color channels per pixel), you want to use ind2rgb (instead of replicating the labels to all channels). Replace rgb_label = repmat(pixel_labels, [1 1 3]); with
rgb_label = ind2rgb(pixel_labels, rand(max(pixel_labels(:)),3));

MATLAB overlaying white area of binary image with rgb image

I am using MATLAB 2012b.
I was able to get the objects outline in an image:
using method of Active Contour Segmentation and the result is in binary mask:
How can I fill the white area of the binary image with the original rgb image?
Basically what I want is to make the background completely black.
Here is my code:
gambarOri = imread(pathGambar);
A = rgb2gray(gambarOri );
mask = zeros(size(A)); mask(10:end-10,10:end-10) = 1;
BW = activecontour(A, mask, 500);
figure, subplot(1, 2, 1), imshow(A), title('Grayscale');
subplot(1, 2, 2), imshow(BW), title('Segmented image in Binary');
You cannon overlay an RGB on a binary image, since the data types do not match. What you can do is to modify your RGB image according to the binary image. For instance you can replace values of the RGB image in false areas of BW with zeros:
% separating RGB channels:
R = gambarOri(:, :, 1);
G = gambarOri(:, :, 2);
B = gambarOri(:, :, 3);
% placing zeros where BW is FALSE:
R(~BW) = 0;
G(~BW) = 0;
B(~BW) = 0;
% concatenate color layers into final result:
blackBG = cat(3, R, G, B);
% figure; imshow(blackBG)
With this result for your provided image:
You can use bsxfun:
blackBG = uint8(bsxfun(#times, double(gambarOri), BW));

Detecting a circle in an image in MATLAB - works in the binary, but not on the original

I wrote a code for detecting a circle in my image.
Image.png :-
Code:-
blueBall1 = imread('Image.png');
t = imtool(blueBall1);
close(t)
r = blueBall1(:, :, 1);
g = blueBall1(:, :, 2);
b = blueBall1(:, :, 3);
figure
subplot(2,2,1),imshow(r),title('R Plane')
subplot(2,2,2),imshow(g),title('G Plane')
subplot(2,2,3),imshow(b),title('B Plane')
justBlue = b - r/2 - g/2;
close all
bw = justBlue > 50;
imshow(bw);
ball1 = bwareaopen(bw, 30);
imshow(ball1);
Rmin=15;Rmax=50;
[centersBright, radiiBright] = imfindcircles(ball1, [Rmin Rmax], ...
'ObjectPolarity','bright','sensitivity',0.83)
hold on
viscircles(centersBright, radiiBright,'LineStyle','--');hold off
imshow(blueBall1),
hold on viscircles(centersBright, radiiBright,'LineStyle','--');hold off
If I make the last two lines like comments, it shows the binary picture where there is circle around the blue ball:
However, the last two lines are for the original image which loads but without the circle around the ball.
Does anyone know how to fix it?
I added some figure commands and moved viscircles to a new line at the end and this is what I get as my final image out:
It is the original image with a circle around the blue ball. Is this what you are looking for?
Here's your code with a couple of changes:
blueBall1 = imread('ballimage.png');
t = imtool(blueBall1);
close(t)
r = blueBall1(:, :, 1);
g = blueBall1(:, :, 2);
b = blueBall1(:, :, 3);
figure;
subplot(2,2,1),imshow(r),title('R Plane')
subplot(2,2,2),imshow(g),title('G Plane')
subplot(2,2,3),imshow(b),title('B Plane')
justBlue = b - r/2 - g/2;
close all
figure;
bw = justBlue > 50;
imshow(bw);
figure;
ball1 = bwareaopen(bw, 30);
imshow(ball1);
Rmin=15;Rmax=50;
[centersBright, radiiBright] = imfindcircles(ball1, [Rmin Rmax], ...
'ObjectPolarity','bright','sensitivity',0.83)
hold on
viscircles(centersBright, radiiBright,'LineStyle','--');hold off
figure;
imshow(blueBall1),
hold on
viscircles(centersBright, radiiBright,'LineStyle','--');hold off