Find number of white/black pixels in binary image - image

I have an binary word image with grid and i want to find the foreground pixels (number of black and white in each segments) in each segments

So I just wanted to get the total number of black pixels for an image and I didn't want to segment it. Didn't feel like having to learn how to segment a matrix.
Easy fix to get the sum of the black pixels:
sum(sum(bw == 0))
Conversely to get the white pixels
sum(sum(bw == 1))
The operation function sum(bw == 0) just gets everything to a [1xn] matrix, so you will need to perform sum and you will get the whole image matrix summed.
Thought that cumsum would do the trick, but sum(sum()) is just better for this case. Tells you how little I know about coding. Have fun with this info, note that I'm just using this to determine the area coverage of a binarized image, but for anything else particularly useful.

Assume your black and white image is bw
sum(bw==0) // number of black pixels
sum(bw==1) // number of white pixels
For each grid find the range in both directions, then apply the same idea.
For example, from x1 to x2 and y1 to y2 is one grid:
sum(bw(x1:x2, y1:y2) == 0) // will give you the black pixels you want

That is easy with logical indexing.
For each segment, do:
n_white=sum(segment(:)==1);
n_black=sum(segment(:)==0);

Related

Matlab detect rectangle from image [duplicate]

I need to know how to align an image in Matlab for further work.
for example I have the next license plate image and I want to recognize all
the digits.
my program works for straight images so, I need to align the image and then
preform the optical recognition system.
The method should be as much as universal that fits for all kinds of plates and in all kinds of angles.
EDIT: I tried to do this with Hough Transform but I didn't Succeed. anybody can help me do to this?
any help will be greatly appreciated.
The solution was first hinted at by #AruniRC in the comments, then implemented by #belisarius in Mathematica. The following is my interpretation in MATLAB.
The idea is basically the same: detect edges using Canny method, find prominent lines using Hough Transform, compute line angles, finally perform a Shearing Transform to align the image.
%# read and crop image
I = imread('http://i.stack.imgur.com/CJHaA.png');
I = I(:,1:end-3,:); %# remove small white band on the side
%# egde detection
BW = edge(rgb2gray(I), 'canny');
%# hough transform
[H T R] = hough(BW);
P = houghpeaks(H, 4, 'threshold',ceil(0.75*max(H(:))));
lines = houghlines(BW, T, R, P);
%# shearing transforma
slopes = vertcat(lines.point2) - vertcat(lines.point1);
slopes = slopes(:,2) ./ slopes(:,1);
TFORM = maketform('affine', [1 -slopes(1) 0 ; 0 1 0 ; 0 0 1]);
II = imtransform(I, TFORM);
Now lets see the results
%# show edges
figure, imshow(BW)
%# show accumlation matrix and peaks
figure, imshow(imadjust(mat2gray(H)), [], 'XData',T, 'YData',R, 'InitialMagnification','fit')
xlabel('\theta (degrees)'), ylabel('\rho'), colormap(hot), colorbar
hold on, plot(T(P(:,2)), R(P(:,1)), 'gs', 'LineWidth',2), hold off
axis on, axis normal
%# show image with lines overlayed, and the aligned/rotated image
figure
subplot(121), imshow(I), hold on
for k = 1:length(lines)
xy = [lines(k).point1; lines(k).point2];
plot(xy(:,1), xy(:,2), 'g.-', 'LineWidth',2);
end, hold off
subplot(122), imshow(II)
In Mathematica, using Edge Detection and Hough Transform:
If you are using some kind of machine learning toolbox for text recognition, try to learn from ALL plates - not only aligned ones. Recognition results should be equally well if you transform the plate or dont, since by transforming, no new informations according to the true number will enhance the image.
If all the images have a dark background like that one, you could binarize the image, fit lines to the top or bottom of the bright area and calculate an affine projection matrix from the line gradient.

Need to automatically eliminate noise in image and outer boundary of a object

i am mechanical engineering student working on a project to automatically detect the weld seam (The seam is a edge that is to be welded) present in a workshop. This gives a basic terminology involved in welding (http://i.imgur.com/Hfwjq0w.jpg).
To separate the weldment from the other objects, i have taken the background image and subtracted the foreground image having the weldment to obatin only the weldment(http://i.imgur.com/v7yBWs1.jpg). After image subtraction,there are the shadow ,glare and remnant noises of subtracted background are still present.
As i want to automatically identify only the weld seam without the outer boundary of weldment, i have tried to detect the edges in the weldment image using canny algorithm and tried to eliminate the isolated noises using the function bwareopen.I have somehow obtained the approximate boundary of weldment and weld seam. The threshold i have used are purely on trial and error approach as dont know a way to automatically set a threshold to detect them.
The problem now i am facing is that i cant specify an definite threshold as this algorithm should be able to identify the seam of any material regardless of its surface texture,glare and shadow present there. I need some assistance to remove the glare,shadow and isolated points from the background subtracted image.
Also i need help to get rid of the outer boundary and obtain only smooth weld seam from starting point to end point.
i have tried to use the following code:
a=imread('imageofworkpiece.jpg'); %http://i.imgur.com/3ngu235.jpg
b=imread('background.jpg'); %http://i.imgur.com/DrF6wC2.jpg
Ip = imsubtract(b,a);
imshow(Ip) % weldment separated %http://i.imgur.com/v7yBWs1.jpg
BW = rgb2gray(Ip);
c=edge(BW,'canny',0.05); % by trial and error
figure;imshow(c) % %http://i.imgur.com/1UQ8E3D.jpg
bw = bwareaopen(c, 100); % by trial and error
figure;imshow(bw) %http://i.imgur.com/Gnjy2aS.jpg
Can anybody please suggest me a adaptive way to set a threhold and remove the outer boundary to detect only the seam? Thank you
Well this doesn't solve your problem of finding an automatic thresholding algorithm. but I can help with isolation the seam. The seam is along the y axis (will this always be the case?) so I used hough transform to isolate only near vertical lines. Normally it finds all lines but I restricted the theta search parameter. The code I'm using now happens to highlight the longest line segment (I got it directly from the matlab website) and it is coincidentally the weld seam. This was purely coincidental. But using your bwareaopened image as input the hough line detector is able to find the seam. Of course it required a bit of playing around to work, so you are stuck at your original problem of finding optimal settings somehow
Maybe this can be a springboard for someone else
a=imread('weldment.jpg'); %http://i.imgur.com/3ngu235.jpg
b=imread('weld_bg.jpg'); %http://i.imgur.com/DrF6wC2.jpg
Ip = imsubtract(b,a);
imshow(Ip) % weldment separated %http://i.imgur.com/v7yBWs1.jpg
BW = rgb2gray(Ip);
c=edge(BW,'canny',0.05); % by trial and error
bw = bwareaopen(c, 100); % by trial and error
figure(1);imshow(c) ;title('canny') % %http://i.imgur.com/1UQ8E3D.jpg
figure(2);imshow(bw);title('bw area open') %http://i.imgur.com/Gnjy2aS.jpg
[H,T,R] = hough(bw,'RhoResolution',1,'Theta',-15:5:15);
figure(3)
imshow(H,[],'XData',T,'YData',R,...
'InitialMagnification','fit');
xlabel('\theta'), ylabel('\rho');
axis on, axis normal, hold on;
P = houghpeaks(H,5,'threshold',ceil(0.5*max(H(:))));
x = T(P(:,2)); y = R(P(:,1));
plot(x,y,'s','color','white');
% Find lines and plot them
lines = houghlines(BW,T,R,P,'FillGap',2,'MinLength',30);
figure(4), imshow(BW), hold on
max_len = 0;
for k = 1:length(lines)
xy = [lines(k).point1; lines(k).point2];
plot(xy(:,1),xy(:,2),'LineWidth',2,'Color','green');
% Plot beginnings and ends of lines
plot(xy(1,1),xy(1,2),'x','LineWidth',2,'Color','yellow');
plot(xy(2,1),xy(2,2),'x','LineWidth',2,'Color','red');
% Determine the endpoints of the longest line segment
len = norm(lines(k).point1 - lines(k).point2);
if ( len > max_len)
max_len = len;
xy_long = xy;
end
end
% highlight the longest line segment
plot(xy_long(:,1),xy_long(:,2),'LineWidth',2,'Color','blue');
from your image it looks like the weld seam will be usually very dark with sharp intensity edge so why don't you use that ?
do not use background
create derivation image
dx[y][x]=pixel[y][x]-pixel[y][x-1]
do this for whole image (if on place then x must decrease in loop!!!)
filter out all derivations lower then thresholds
if (|dx[y][x]|<threshold) dx[y][x]=0; else pixel[y][x]=255;` // or what ever values you use
how to obtain threshold value ?
compute min and max intensity and set threshold as (max-min)*scale where scale is value lower then 1.0 (start with 0.02 or 0.1 for example ...
do this also for y axis
so compute dy[][]... and combine dx[][] and dy[][] together. Either with OR or by AND logical functions
filter out artifacts
you can use morphologic filters or smooth threshold for this. After all this you will have mask of pixels of weld seam
if you need boundig box then just loop through all pixels and remember min,max x,y coords ...
[Notes]
if your images will have good lighting then you can ignore the derivation and threshold the intensity directly with something like:
threshold = 0.5*(average_intensity+lowest_intensity)
if you want really fully automate this then you have to use adaptive thresholds. So try more thresholds in a loop and remember result closest to desired output based on geometry size,position etc ...
[edit1] finally have some time/mood for this so
Intensity image threshold
you provided just single image which is far from enough to make reliable algorithm. This is the result
as you can see without further processing this is not good approach
Derivation image threshold
threshold derivation by x (10%)
threshold derivation by y (5%)
AND combination of both 10% di/dx and 1.5% di/dy
The code in C++ looks like this (sorry do not use Matlab):
int x,y,i,i0,i1,tr2,tr3;
pic1=pic0; // copy input image pic0 to pic1
pic2=pic0; // copy input image pic0 to pic2 (just to resize to desired size for derivation)
pic3=pic0; // copy input image pic0 to pic3 (just to resize to desired size for derivation)
pic1.rgb2i(); // RGB -> grayscale
// abs derivate by x
for (y=pic1.ys-1;y>0;y--)
for (x=pic1.xs-1;x>0;x--)
{
i0=pic1.p[y][x ].dd;
i1=pic1.p[y][x-1].dd;
i=i0-i1; if (i<0) i=-i;
pic2.p[y][x].dd=i;
}
// compute min,max derivation
i0=pic2.p[1][1].dd; i1=i0;
for (y=1;y<pic1.ys;y++)
for (x=1;x<pic1.xs;x++)
{
i=pic2.p[y][x].dd;
if (i0>i) i0=i;
if (i1<i) i1=i;
}
tr2=i0+((i1-i0)*100/1000);
// abs derivate by y
for (y=pic1.ys-1;y>0;y--)
for (x=pic1.xs-1;x>0;x--)
{
i0=pic1.p[y ][x].dd;
i1=pic1.p[y-1][x].dd;
i=i0-i1; if (i<0) i=-i;
pic3.p[y][x].dd=i;
}
// compute min,max derivation
i0=pic3.p[1][1].dd; i1=i0;
for (y=1;y<pic1.ys;y++)
for (x=1;x<pic1.xs;x++)
{
i=pic3.p[y][x].dd;
if (i0>i) i0=i;
if (i1<i) i1=i;
}
tr3=i0+((i1-i0)*15/1000);
// threshold the derivation images and combine them
for (y=1;y<pic1.ys;y++)
for (x=1;x<pic1.xs;x++)
{
// copy original (pic0) pixel for non thresholded areas the rest fill with green color
if ((pic2.p[y][x].dd>=tr2)&&(pic3.p[y][x].dd>=tr3)) i=0x00FF00;
else i=pic0.p[y][x].dd;
pic1.p[y][x].dd=i;
}
pic0 is input image
pic1 is output image
pic2,pic3 are just temporary storage for derivations
pic?.xy,pic?.ys is the size of pic?
pic.p[y][x].dd is pixel axes (dd means access pixel as DWORD ...)
as you can see there is a lot of stuff around (nod visible in the first image you provided) so you need to process this further
segmentate and separate...,
use hough transform ...
filter out small artifacts ...
identify object by expected geometry properties (aspect ratio,position,size)
Adaptive thresholds:
you need for this to know the desired output image properties (not possible to reliably deduce from single image input) then create function that do the above processing with variable tr2,tr3. Try in loop more options of tr2,tr3 (loop through all values or iterate to better results and remember the best output (so you also need some function that detects the quality of output) for example:
quality=0.0; param=0.0;
for (a=0.2;a<=0.8;a+=0.1)
{
pic1=process_image(pic0,a);
q=detect_quality(pic1);
if (q>quality) { quality=q; param=a; pico=pic1; }
}
after this the pic1 should hold the relatively best threshold image ... You should process like this all threshold separately inside the process_image the targeted threshold must be scaled by a for example tr2=i0+((i1-i0)*a);

Break down picture in reactangles

I'm looking for an algorithm.
I want to draw a image (2d-array of pixels) with the lowest number of rectangles . It's possible to overwrite already drawed areas by a new rectangles.
In the first step I convert every pixel of the picture to a quad with the size 1x1 and a color. Than I want to reduce the number of objects by creating bigger rectangles.
In the end I want an array of rectangles. When I iterate over it and draw it on the pane, I want to have the original picture.
Is there any algorithm?
The runtime doesn't matter.
Example1:
|.bl.|.bl.|.bl.|-----|.bl...........|
|.bl.|.gr.|.bl.| -> |...............| + |.gr.|
|.bl.|.bl.|.bl.|-----|..............|
bl = black, gr = green
Example2:
|....|....|.bl.|
|.bl.|.bl.|.bl.| --> |.bl.|.bl.|.bl.| + |.bl.|
|.bl.|.bl.|.bl.|-----|.bl.|.bl.|.bl.|
I was looking for Quad Tree Compression :)
http://www.gitta.info/DataCompress/en/html/rastercomp_chain.html

count number of non gray pixels in RGB image in matlab

I have a RGB image which has only black and white squares. I want to count number to non gray pixels in this image. I am new to matlab. I want to check the quality of image as it should only contain black and white pixels.Actually I have undistorted this image due that some colored fringes are appeared.I want to know the how many color are introduced to check the quality of the image.
using matlab to get counts of specific pixel values in an image.
Images are RGBA <512x512x4 uint8> when read into matlab (although we can disregard the alpha channel).
Something like this
count = sum(im(:, :, 1) == 255 & im(:, :, 3) == 255 & im(:, :, 3) == 255);
will give you the count of such pixels. Replace sum with find to get the indices of those pixels if you need that.
A pixel is said to be gray if its R,G,B components are all same.
Using this logic
%// checking for equality of R,G,B values
B = any(diff(im,[],3),3); %// selecting only non-gray pixels
count = sum(B(:)); %// Number of non-gray pixels
PS: This answer is tailored from this and this answer.

Detect a rectangle bound of an character or object in black/white or binary image

I'm developing a handwriting recognition project. one of the requirements of this project is getting an image input, this image only contains some character object in a random location, and firstly I must extract this characters to process in next step.
Now I'm confusing a hard problem like that: how to extract one character from black/white (binary)image or how to draw a bound rectangle of a character in black - white (binary) image?
Thanks very much!
If you are using MATLAB (which I hope you are, since it it awesome for tasks like these), I suggest you look into the built in function bwlabel() and regionprops(). These should be enough to segment out all the characters and get their bounding box information.
Some sample code is given below:
%Read image
Im = imread('im1.jpg');
%Make binary
Im(Im < 128) = 1;
Im(Im >= 128) = 0;
%Segment out all connected regions
ImL = bwlabel(Im);
%Get labels for all distinct regions
labels = unique(ImL);
%Remove label 0, corresponding to background
labels(labels==0) = [];
%Get bounding box for each segmentation
Character = struct('BoundingBox',zeros(1,4));
nrValidDetections = 0;
for i=1:length(labels)
D = regionprops(ImL==labels(i));
if D.Area > 10
nrValidDetections = nrValidDetections + 1;
Character(nrValidDetections).BoundingBox = D.BoundingBox;
end
end
%Visualize results
figure(1);
imagesc(ImL);
xlim([0 200]);
for i=1:nrValidDetections
rectangle('Position',[Character(i).BoundingBox(1) ...
Character(i).BoundingBox(2) ...
Character(i).BoundingBox(3) ...
Character(i).BoundingBox(4)]);
end
The image I read in here are from 0-255, so I have to threshold it to make it binary. As dots above i and j can be a problem, I also threshold on the number of pixels which make up the distinct region.
The result can be seen here:
https://www.sugarsync.com/pf/D775999_6750989_128710
The better way to extract the character in my case was the segmentation for histogram i only can share with you some papers.
http://cut.by/j7LE8
http://cut.by/PWJf1
may be this can help you
One simple option is to use an exhaustive search, like (assuming text is black and background is white):
Starting from the leftmost column, step through all the rows checking for a black pixel.
When you encounter your first black pixel, save your current column index as left.
Continue traversing the columns until you encounter a column with no black pixels in it, save this column index as right.
Now traverse the rows in a similar fashion, starting from the topmost row and stepping through each column in that row.
When you encounter your first black pixel, save your current row index as top.
Continue traversing the rows until you find one with no black pixels in it, and save this row as `bottom.
You character will be contained within the box defined by (left - 1, top - 1) as the top-left corner and (right, bottom) as the bottom-right corner.

Resources