Reputation: 21
I am working on a project that consists in using a camera to detect if an electronic component has been soldered or not. The program has to be able to trigger the snapshot when a PLC asks for it, analize it and send a pass/fail sign back to the plc.
As I'm a MATLAB begginer I have been searching for information to know if it's feasible and to get a basic idea of where to start.
My idea would be to count how many pixels have a silver or gold tone in a defined zone. If it's mainly gold it means that it hasn't been soldered.
My question is, how would you do it to obtain the number of pixels that have a color inside a defined range inside a region of a webcam image?
I have found this but it's for an exact color instead of a range.
count = sum(im(:, :, 1) == 255 & im(:, :, 3) == 255 & im(:, :, 3) == 255);
Upvotes: 1
Views: 3593
Reputation: 21
In the end I used the function I posted but using a small region of interest.
I need to draw a square arround the yellow zones, any suggestions?
I'm attaching the code so there is some feedback (I'm not sure how to attach it, maybe you are not going to see it). The comments are in catalan but you won't have trouble understanding what I've done.
Thank you all!
clear all
clc
info = imaqhwinfo('winvideo') %Defineix origen de video
dev=info.DeviceInfo
vid=videoinput('winvideo',1)
vid.ROIPosition=[200 300 355 400]; %Zona a analitzar [iniciX, iniciY, ampladaX,
alçadaY]
vid.FramesPerTrigger=5; %Millora la qualitat de la foto
src.Sharpness=5;
img=getsnapshot(vid); %Dispara foto
count = sum((img(:, :, 1) >= 150 & img(:, :, 1) <= 255) & (img(:, :, 2) >= 100 & img(:,
:, 2) <= 255) & (img(:, :, 3) >= 0 & img(:, :, 3) <= 100));
numP=sum(count(1,:)) %Nombre de píxels en el rang de color donat
%ARA DETECTA GROC/DAURAT
dimT=size(img(:,:,1)); %Nombre de píxels total en la imatge
numT=dimT(1)*dimT(2)
Percentatge=numP/numT*100 %Percentatge de color en la imatge
%Hold on
%Draw square
%imshow(img)
%Hold off
Upvotes: 1
Reputation: 208107
No need for epensive MATLAB, you can do that really easily in ImageMagick which is free and available here
So, basically you use this command:
convert yourpicture.jpg -colorspace rgb -colors 256 -depth 8 txt:
and it gives you this - a listing of all the pixels and their values:
# ImageMagick pixel enumeration: 32,32,255,rgb
0,0: (255,255,0) #FFFF00 rgb(255,255,0)
1,0: (255,255,0) #FFFF00 rgb(255,255,0)
2,0: (255,255,0) #FFFF00 rgb(255,255,0)
Then you can get rid of all the superfluous stuff and just look at the RGB values like this:
convert yourimage.jpg -colorspace rgb -colors 256 -depth 8 txt: | \
awk -F'[()]' '/^[0-9]/{print $4}' | \
awk -F, '{R=$1;G=$2;B=$3; print R,G,B}'
Sample Output
0 255 255
0 255 255
8 156 8
8 156 8
0 55 0
0 55 0
0 55 0
8 156 8
The above code will take your image, whether JPEG or PNG or TIFF and list all the RGB values of all the pixels.
If we now assume gold is RGB 255,215,0 we can do this:
# Find gold pixels +/- fuzz factor of 25
#
convert yourpicture.jpg -colorspace rgb -colors 256 -depth 8 txt: | \
awk -F'[()]' '/^[0-9]/{print $4}' | \
awk -F, 'BEGIN {gold=0}
{R=$1;G=$2;B=$3; if((R>230) && (G>190) && (G<240) && (B<25))gold++}
END {print "Gold pixels found: ",gold}'
If you want to work with hue/saturation and value, you can equally do that in ImageMagick like this:
# Find gold pixels +/- fuzz Hue=14
#
convert yourpicture.jpg -colorspace hsv -depth 8 txt:| \
awk -F'[()]' '/^[0-9]/{print $4}' | \
awk -F, 'BEGIN {gold=0}
{H=$1; if((H>11)&&(H<16))gold++}
END {print "Gold pixels found: ",gold}'
I should point out that the range of Hue is 0-360, so if we search for 14 (+/- fuzz) we are looking for a Hue of 14% of 360, i.e. Hue=50 which corresponds to gold.
If you want to visualise which pixels are selected and counted, you can do this:
convert pcb.jpg -channel R -fx "hue>0.09&&hue<0.11?1:0" -separate -background black -channel R -combine pcb_gold.jpg
which, given this input image, will produce this result:
Even easier than the foregoing, is this little script that does all you want!
#!/bin/bash
# Define our gold colour
#
gold="rgb(255,215,0)"
# Convert all pixels in the image that are gold +/-35% into red. Write output to "out.jpg"
# ... and also in text format so we can count the red pixels with "grep -c"
convert pcb.jpg -fuzz 35% -fill red -opaque "$gold" -depth 8 -colorspace rgb -write txt: out.jpg | grep -c FF0000
which produces this image, and the gold pixel count of 1076.
Upvotes: 0
Reputation: 2993
Here are two methods to pick pixels within a pre-defined color range.
_
clear;clc;close all
I_rgb = imread('peppers.png');
figure(1)
imshow(I_rgb)
% hue distance in HSV space
I_hsv = rgb2hsv(I_rgb);
red_h = 358/360; % (normalized) hue for the red color
O_select = abs(I_hsv(:,:,1)-red_h)<=.05;
figure(2)
imshow(O_select)
O_hsv = I_hsv;
O_hsv(:,:,2) = O_hsv(:,:,2).*O_select;
O_rgb = hsv2rgb(O_hsv);
figure(3)
imshow(O_rgb)
% Euclidean distance in RGB space
red_rgb = reshape([188;28;38],[1,1,3]); % rgb coordinates for the red color
O_distance = sqrt(sum(bsxfun(@minus, double(I_rgb), red_rgb).^2, 3));
O_select = O_distance < 50;
figure(4)
imshow(O_select);
O_hsv = I_hsv;
O_hsv(:,:,2) = O_hsv(:,:,2).*O_select;
O_rgb = hsv2rgb(O_hsv);
figure(5)
imshow(O_rgb)
You can define multiple colors to pick, and combine several O_select
's using things like or
into your final result.
Upvotes: 0