Break down picture in reactangles - image

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

Related

Find number of white/black pixels in binary 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);

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.

Draw a horizontal line on an image whose row corresponds to the largest count of dark pixels

I wish to draw a horizontal line on a binary image in MATLAB which has the maximum amount of black pixels. So in this word for example:
... I have to identify the horizontal line with most pixels.
I understand that I can open the binary image variable editor, and plot a row which has maximum zeroes however that doesn't seem to work.
I have to make a baseline of this word like this:
... as the output assuming that the maximum pixels lie where I drew the line.
Purely going by your definition, you want to figure out the row that has the largest amount of black pixels. Simply sum over all columns of each row and find the maximum. Then when you're done, locate the row with the largest count and set this line to red.
Something like this comes to mind. I'm going to read your image from StackOverflow directly and am going to use the image processing toolbox to help me with this analysis:
%// Read image from SO
im = imread('http://s15.postimg.org/cwg2sxnwr/mathworksss.png');
%// Keep a copy of a binary version
im_bw = im2bw(im);
%// Sum over all of the columns and look for dark pixels
row_sums = sum(~im_bw, 2);
%// Find row with max sum
[~,row_max] = max(row_sums);
%// Draw a red line through the original image as it's in RGB
im(row_max,:,1) = 255;
im(row_max,:,2:3) = 0;
%// Show the image
imshow(im);
The first image reads in the image directly from SO and puts it into the MATLAB workspace. The next line thresholds the image to binary to allow the analysis to be easier. We also keep a copy of the original image so we can mark the baseline with red. The next line after that uses sum and sums over every column of each row individually and adds up the black pixels. This is achieved by inverting the binary image so that dark pixels become bright to facilitate the summing. We then use max to figure out the row with the largest sum and that's done by looking at the second output of max. Once we find this location, we use this row and set all of the pixels in this row to red, or RGB = (255,0,0).
I get this image:
Now the above code draws a line from the left to the right. If you wanted to limit this and only draw a red line where there is text, perhaps find the left most and right most dark pixel and add a bit of breathing room to them, then draw a line through.... something like this comes to mind:
%// Read image from SO
im = imread('http://s15.postimg.org/cwg2sxnwr/mathworksss.png');
%// Keep a copy of a binary version
im_bw = im2bw(im);
%// Sum over all of the columns and look for dark pixels
row_sums = sum(~im_bw, 2);
%// Find row with max sum
[~,row_max] = max(row_sums);
%// Find left most and right most black columns
[~,left_most] = find(~im_bw,1,'first');
[~,right_most] = find(~im_bw,1,'last');
%// Buffer for drawing the line before the first and after the last column
buf = 20;
%// Draw the line
im(row_max,left_most-buf:right_most+buf,1) = 255;
im(row_max,left_most-buf:right_most+buf,2:3) = 0;
%// Show the image
imshow(im);
As you can see, most of the code remains the same (reading in the image, thresholding, column summing and max) but towards the end, I use find to find the first and last instance of a black pixel with respect to the columns. I then use these columns with the same maximum row found earlier, then subtracting the left most black column pixel location and adding the right most black column pixel location by a buffer amount (I chose 20 here), then setting the line of pixels within this region to red.
We get:
Now, it is your wish to find the row with the second highest sum and draw another line through that row. That's not bad to do. However, this will require some post-processing because the outer edges of each character is not a single pixel thick... so the second highest sum may actually still give you a row that is around the first maximum. As such, I would suggest shrinking the text slightly then applying the row sum logic again. You can do this with morphological binary erosion with a small structuring element... say, a 3 x 3 square. This can be done with imerode for the erosion and using strel to specify the square structuring element.
You'd apply the row sum logic to this new image, but then use these results and draw on the original image. You don't want to operate on this new image because it looks like there are some areas of the text that are a single pixel thick and these will be eliminated after erosion.
Something like this comes to mind:
%// Read image from SO
im = imread('http://s15.postimg.org/cwg2sxnwr/mathworksss.png');
%// Keep a copy of a binary version - also invert for ease
im_bw = ~im2bw(im);
%// Slightly erode the text
im_bw = imerode(im_bw, strel('square', 3));
%// Sum over all of the columns and look for dark pixels
row_sums = sum(im_bw, 2);
%// Sort the column sums in descending order and figure out the two highest sums
[~,ind_sort] = sort(row_sums,'descend');
%// First highest sum is the bottom - mark as red
red_row1 = ind_sort(1);
%// Second highest sum is the middle - mark as red too
red_row2 = ind_sort(2);
%// Find left most and right most black columns
[~,left_most] = find(im_bw,1,'first');
[~,right_most] = find(im_bw,1,'last');
%// Buffer for drawing the line before the first and after the last column
buf = 20;
%// Draw the two red lines
im(red_row1,left_most-buf:right_most+buf,1) = 255;
im(red_row1,left_most-buf:right_most+buf,2:3) = 0;
im(red_row2,left_most-buf:right_most+buf,1) = 255;
im(red_row2,left_most-buf:right_most+buf,2:3) = 0;
%// Show the image
imshow(im);
As you can see, most of the logic is the same. The only thing I really changed was that I eroded the image, sorted the row sums in descending order and extracted the first two locations that are the highest. I then repeated the logic to draw a line through the row, but instead of one row, we have two now.
We get:

How to filter binary image with unwanted region and hole region

I have a hard problem that need your help. I have a binary image that maintains some unwanted region (small white dot) and hole regions (in figure 1).My idea is that the first I will remove unwanted region by calculating area these region and then filter with small area value.At the second step, I fill in hole region to make clear image.What do you think best method to fill in hole region. Do you have any idea to resolve it. Could you help me implement it by matlab. Thank you so much. This is my reference code for remove unwanted region. But it need threshold term. You can download image test at here
function exImage=rmUnwantedRegion(Img,threshold)
lb = bwlabel(Img);
st = regionprops(lb, 'Area', 'PixelIdxList' );
toRemove = [st.Area] <threshold; % fix your threshold here
exImage = Img;
exImage( vertcat(st(toRemove).PixelIdxList ) ) = 0; % remove
end
Here is an example implementation based on my comment:
subplot(1,3,1), imshow(input);
title('Original Image');
Calculating the opening of the image:
openInput=bwareaopen(input, 20);
subplot(1,3,2), imshow(bwareaopen(input, 20));
title('Opened Image');
And the subsequent closing:
ClosedInput = imclose(openInput,ones(10));
subplot(1,3,3), imshow(ClosedInput);
title('Closed Image');
Result:
Assuming white pixel is 1
Black is 0
Step 1:
Use convultion matrix (http://en.wikipedia.org/wiki/Kernel_%28image_processing%29)
with blur filter
Step 2:
Treshold each pixel with some static value (for example 0.5)
if pixel is >0.5 pixel = 1
else pixel = 0
This looks like a job for binary dilation and erosion. Generally an erosion is done first to remove unwanted noise and then dilation is performed with the same structuring element to fill in the gaps left by the erosion. Matlab uses strel to create structuring elements for morphological operations. You can also read about morphological operators here
Example:
SE=strel('square',5);
im_eroded=imerode(im,SE);
im_dilated=imdilate(im_eroded,SE);
You need to do an erosion (Wikipedia or Matlab) followed by a dilation (Wikipedia or Matlab). This is done using the imerode and the imdilate functions in Matlab.
Doing this require to specify the size of the element eroding and dilating using the strel function with a shape ('square', 'disk', 'octagon', etc.) and a size.
SE=strel('disk',5);
im_eroded=imerode(im,SE);
im_dilated=imdilate(im_eroded,SE);

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