I have an RGB image of size MxNx3. Let's imagine we have a reflection line somewhere in the bottom half of the image. How do I reflect all the points above the line onto the line? I know what I need to do but I can't get it right on MATLAB. Thanks for any help.
For example, in the image below the blue line is the reflection line.
Code
%%// Read input image
img =imread(IMG_FILEPATH);
%%// Let user select the mask, top of which will basically act
%%// as the reflection line
figure,imshow(img)
[mask,xi,yi] = roipoly(img);
%%// Remove the last element as that is same as the first one
xi(end)=[];
yi(end)=[];
%%// Find the two corner points each on the left and right sides of the mask
pt_matrix = [xi yi]
[val,ind] = sort(xi)
left_two_pts = pt_matrix(ind(1:2),:)
right_two_pts = pt_matrix(ind(end-1:end),:)
four_pts = round([left_two_pts;right_two_pts])
%%// Remove a 5x5 neighborhood around the four corners, so that biggest
%%// blob that is the line could be separated out
BW1 = edge(mask,'canny');
for k = 1:4
BW1(four_pts(k,2)-2:four_pts(k,2)+2,four_pts(k,1)-2:four_pts(k,2)+1) = 0;
end
%%// Get the biggest blob that is the reflection line
[L, num] = bwlabel(BW1);
counts = sum(bsxfun(#eq,L(:),1:num));
[~,ind] = max(counts);
BW1 = (L==ind);
%%// Connect the endpoints of the line to left and right sides of the image
xlimit = [find(sum(BW1,1),1) find(sum(BW1,1),1,'last')];
[row1,col1] = ind2sub(size(BW1),find(BW1));
BW1(row1(1),1:col1(1)-1)=1;
BW1(row1(end),col1(end)+1:end)=1;
%%// Select only one per column for the reflection
[xt0,yt0] = find(BW1);
[yt1,a2,a3] =unique(yt0,'first');
xt1=xt0(a2);
sz1 = size(BW1,1)-xt1;
%%// Perform the reflection
for k = 1:numel(yt1)
img(xt1(k):end,k,:) = img(xt1(k):-1:xt1(k)-sz1(k),k,:);
end
figure,imshow(img)
Typical mask with roipoly would look like -
Output
Note: User has to select exactly two points on the left side to represent the left side border of the mask and exactly two points on the right side for the right side border. Also, there must enough image pixels on top of the line to reflect over the line.
I'm assuming the line is stored in a mask, as stated by the OP. I will assume the mask is black above the line and white below it. Here is a "fancy" way to solve the problem. :)
% 1. Open your image (MxNx3 matrix).
img = im2double(imread('original.png'));
% 2. Open your 'line image' as a logical array (MxNx3 matrix)
line = imread('line.png') > 0;
% 3. Now, we will "align" the upper part of the image based on the line,
% so that the line will be straight at the bottom of the image. We will
% do that by sorting the 'line image', moving the ones of the mask
% above. The code was adapted from:
% http://www.mathworks.com/matlabcentral/newsreader/view_thread/28715
upper = zeros(size(line));
upper(~line) = -1;
upper = sort(upper, 'descend');
upper(upper == -1) = img(~line);
% 4. Let's concatenate both the image with it's mirror below.
imgConcat = [upper; upper(end:-1:1, :, :)];
% 5. Also, The line mask will be concatenated to it's negative, and we'll
% invert the order of the rows.
lineConcat = [line; ~line];
lineConcat = lineConcat(end:-1:1,:,:);
% 6. Now we repeat the "alignment procedure" used on step 4 so that the
% image will be positioned on the upper part. We will also remove the
% lower part, now containing only zeros.
mirror = zeros(size(lineConcat));
mirror(lineConcat) = -1;
mirror = sort(mirror, 'ascend');
mirror(mirror == -1) = imgConcat(lineConcat);
mirror = mirror(1:end/2,:,:);
Here you see the result (step by step);
To generate that image, I used this code:
% Display the results, step by step (final result is in the 'mirror' matrix).
subplot(2,3,1), imshow(img, []); title('Step 1. Original image')
subplot(2,3,2), imshow(double(line), []); title('Step 2. Line image');
subplot(2,3,3), imshow(upper, []); title('Step 3. Image "alignment"');
subplot(2,3,4), imshow(imgConcat, []); title('Step 4. Mirror concatenation');
subplot(2,3,5), imshow(double(lineConcat), []); title('Step 5. Mask concatenation');
subplot(2,3,6), imshow(mirror, []); title('Step 6. Result by a final alignment');
Assuming that the line is already defined, the simple way to go about this would be to scan each column and, starting at the location of the line, copy as many elements from above the line as will fit below the line, in reverse order.
So for each column c, let line[c] be the row number of the line in that column. Then
maxR = size(c);
c(line[c]:end) = c(line[c]-1:-1:line[c]-(maxR - line[c] + 1));
That part at the end, line[c]-(maxR - line[c] + 1) is what tells it how much to copy. It just takes the distance between the bottom of the column to the line and uses that as the number of pixels to copy.
Of course this has to be generalized to account for 3 channels, but I didn't want to clutter up the concept. Other than that, you just have to put that in a loop over all the columns, c.
This also assumes that there is enough data above the line to fill the area below the line. If not, you'll have to decide how to handle this case.
I'm sure there are ways to vectorize this and take out the loop, but I'll leave that to the experts :)
Related
I'm working on images with overlapping line shapes (left plot). Ultimately I want to segment single objects. I'm working with a Hough transform to achieve this and it works well in finding lines of (significantly) different orientation - e.g. represented by the two maxima in the hough space below (middle plot).
the green and yellow lines (left plot) and crosses (right plot) stem from an approach to do something with the thickness of the line. I couldn't figure out how to extract a broad line though, so I didn't follow up.
I'm aware of the ambiguity of assigning the "overlapping pixels". I will address that later.
Since I don't know, how many line objects one connected region may contain, my idea is to iteratively extract the object corresponding to the hough line with the highest activation (here painted in blue), i.e. remove the line shaped object from the image, so that the next iteration will find only the other line.
But how do I detect, which pixels belong to the line shaped object?
The function hough_bin_pixels(img, theta, rho, P) (from here - shown in the right plot) gives pixels corresponding to the particular line. But that obviously is too thin of a line to represent the object.
Is there a way to segment/detect the whole object that is orientied along the strongest houghline?
The key is knowing that thick lines in the original image translate to wider peaks on the Hough Transform. This image shows the peaks of a thin and a thick line.
You can use any strategy you like to group all the pixels/accumulator bins of each peak together. I would recommend using multithresh and imquantize to convert it to a BW image, and then bwlabel to label the connected components. You could also use any number of other clustering/segmentation strategies. The only potentially tricky part is figuring out the appropriate thresholding levels. If you can't get anything suitable for your application, err on the side of including too much because you can always get rid of erroneous pixels later.
Here are the peaks of the Hough Transform after thresholding (left) and labeling (right)
Once you have the peak regions, you can find out which pixels in the original image contributed to each accumulator bin using hough_bin_pixels. Then, for each peak region, combine the results of hough_bin_pixels for every bin that is part of the region.
Here is the code I threw together to create the sample images. I'm just getting back into matlab after not using it for a while, so please forgive the sloppy code.
% Create an image
image = zeros(100,100);
for i = 10:90
image(100-i,i)=1;
end;
image(10:90, 30:35) = 1;
figure, imshow(image); % Fig. 1 -- Original Image
% Hough Transform
[H, theta_vals, rho_vals] = hough(image);
figure, imshow(mat2gray(H)); % Fig. 2 -- Hough Transform
% Thresholding
thresh = multithresh(H,4);
q_image = imquantize(H, thresh);
q_image(q_image < 4) = 0;
q_image(q_image > 0) = 1;
figure, imshow(q_image) % Fig. 3 -- Thresholded Peaks
% Label connected components
L = bwlabel(q_image);
figure, imshow(label2rgb(L, prism)) % Fig. 4 -- Labeled peaks
% Reconstruct the lines
[r, c] = find(L(:,:)==1);
segmented_im = hough_bin_pixels(image, theta_vals, rho_vals, [r(1) c(1)]);
for i = 1:size(r(:))
seg_part = hough_bin_pixels(image, theta_vals, rho_vals, [r(i) c(i)]);
segmented_im(seg_part==1) = 1;
end
region1 = segmented_im;
[r, c] = find(L(:,:)==2);
segmented_im = hough_bin_pixels(image, theta_vals, rho_vals, [r(1) c(1)]);
for i = 1:size(r(:))
seg_part = hough_bin_pixels(image, theta_vals, rho_vals, [r(i) c(i)]);
segmented_im(seg_part==1) = 1;
end
region2 = segmented_im;
figure, imshow([region1 ones(100, 1) region2]) % Fig. 5 -- Segmented lines
% Overlay and display
out = cat(3, image, region1, region2);
figure, imshow(out); % Fig. 6 -- For fun, both regions overlaid on original image
I'm making an image processing project and I have stuck in one the project's steps. Here is the situation;
This is my mask:
and I want to detect the maximum-sized rectangle that can fit into this mask like this.
I'm using MATLAB for my project. Do you know any fast way to accomplish this aim. Any code sample, approach or technique would be great.
EDIT 1 : The two algorithms below are works with lot's of the cases. But both of them give wrong results in some difficult cases. I'am using both of them in my project.
This approach starts with the entire image and shrinks each border in turn pixel-by-pixel until it finds an acceptable rectangle.
It takes ~0.02 seconds to run on the example image, so it's reasonably fast.
EDIT: I should clarify that this isn't meant to be a universal solution. This algorithm relies on the rectangle being centered and having roughly the same aspect ratio as the image itself. However, in the cases where it is appropriate, it is fast. #DanielHsH offered a solution which they claim works in all cases.
The code:
clear; clc;
tic;
%% // read image
imrgb= imread('box.png');
im = im2bw(rgb2gray(imrgb)); %// binarize image
im = 1-im; %// convert "empty" regions to 0 intensity
[rows,cols] = size(im);
%% // set up initial parameters
ULrow = 1; %// upper-left row (param #1)
ULcol = 1; %// upper-left column (param #2)
BRrow = rows; %// bottom-right row (param #3)
BRcol = cols; %// bottom-right column (param #4)
parameters = 1:4; %// parameters left to be updated
pidx = 0; %// index of parameter currently being updated
%% // shrink region until acceptable
while ~isempty(parameters); %// update until all parameters reach bounds
%// 1. update parameter number
pidx = pidx+1;
pidx = mod( pidx-1, length(parameters) ) + 1;
p = parameters(pidx); %// current parameter number
%// 2. update current parameter
if p==1; ULrow = ULrow+1; end;
if p==2; ULcol = ULcol+1; end;
if p==3; BRrow = BRrow-1; end;
if p==4; BRcol = BRcol-1; end;
%// 3. grab newest part of region (row or column)
if p==1; region = im(ULrow,ULcol:BRcol); end;
if p==2; region = im(ULrow:BRrow,ULcol); end;
if p==3; region = im(BRrow,ULcol:BRcol); end;
if p==4; region = im(ULrow:BRrow,BRcol); end;
%// 4. if the new region has only zeros, stop shrinking the current parameter
if isempty(find(region,1))
parameters(pidx) = [];
end
end
toc;
params = [ULrow ULcol BRrow BRcol]
area = (BRrow-ULrow)*(BRcol-ULcol)
The results for this image:
Elapsed time is 0.027032 seconds.
params =
10 25 457 471
area =
199362
Code to visualize results:
imrgb(params(1):params(3),params(2):params(4),1) = 0;
imrgb(params(1):params(3),params(2):params(4),2) = 255;
imrgb(params(1):params(3),params(2):params(4),3) = 255;
imshow(imrgb);
Another example image:
Here is a correct answer.
You must use dynamic programming! Other methods of direct calculation (like cutting 1 pixel from each edge) might produce sub-optimal results. My method guarantees that it selects the largest possible rectangle that fits in the mask. I assume that the mask has 1 big convex white blob of any shape with black background around it.
I wrote 2 methods. findRect() which finds the best possible square (starting on x,y with length l). The second method LargestInscribedImage() is an example of how to find any rectangle (of any aspect ratio). The trick is to resize the mask image, find a square and resize it back.
In my example the method finds the larges rectangle that can be fit in the mask having the same aspect ration as the mask image. For example if the mask image is of size 100x200 pixels than the algorithm will find the largest rectangle having aspect ratio 1:2.
% ----------------------------------------------------------
function LargestInscribedImage()
% ----------------------------------------------------------
close all
im = double(imread('aa.bmp')); % Balck and white image of your mask
im = im(:,:,1); % If it is colored RGB take only one of the channels
b = imresize(im,[size(im,1) size(im,1)]); Make the mask square by resizing it by its aspect ratio.
SC = 1; % Put 2..4 to scale down the image an speed up the algorithm
[x1,y1,l1] = findRect(b,SC); % Lunch the dyn prog algorithm
[x2,y2,l2] = findRect(rot90(b),SC); % rotate the image by 90deg and solve
% Rotate back: x2,y2 according to rot90
tmp = x2;
x2 = size(im,1)/SC-y2-l2;
y2 = tmp;
% Select the best solution of the above (for the original image and for the rotated by 90degrees
if (l1>=l2)
corn = sqCorn(x1,y1,l1);
else
corn = sqCorn(x2,y2,l2);
end
b = imresize(b,1/SC);
figure;imshow(b>0); hold on;
plot(corn(1,:),corn(2,:),'O')
corn = corn*SC;
corn(1,:) = corn(1,:)*size(im,2)/size(im,1);
figure;imshow(im); hold on;
plot(corn(1,:),corn(2,:),'O')
end
function corn = sqCorn(x,y,l)
corn = [x,y;x,y+l;x+l,y;x+l,y+l]';
end
% ----------------------------------------------------------
function [x,y,l] = findRect(b,SC)
b = imresize(b,1/SC);
res = zeros(size(b,1),size(b,2),3);
% initialize first col
for i = 1:1:size(b,1)
if (b(i,1) > 0)
res(i,1,:) = [i,1,0];
end
end
% initialize first row
for i = 1:1:size(b,2)
if (b(1,i) > 0)
res(1,i,:) = [1,i,0];
end
end
% DynProg
for i = 2:1:size(b,1)
for j = 2:1:size(b,2)
isWhite = b(i,j) > 0;
if (~isWhite)
res(i,j,:)=res(i-1,j-1,:); % copy
else
if (b(i-1,j-1)>0) % continuous line
lineBeg = [res(i-1,j-1,1),res(i-1,j-1,2)];
lineLenght = res(i-1,j-1,3);
if ((b(lineBeg(1),j)>0)&&(b(i,lineBeg(2))>0)) % if second diag is good
res(i,j,:) = [lineBeg,lineLenght+1];
else
res(i,j,:)=res(i-1,j-1,:); % copy since line has ended
end
else
res(i,j,:) = [i,j,0]; % Line start
end
end
end
end
% check last col
[maxValCol,WhereCol] = max(res(:,end,3));
% check last row
[maxValRow,WhereRow] = max(res(end,:,3));
% Find max
x= 0; y = 0; l = 0;
if (maxValCol>maxValRow)
y = res(WhereCol,end,1);
x = res(WhereCol,end,2);
l = maxValCol;
else
y = res(end,WhereRow,1);
x = res(end,WhereRow,2);
l = maxValRow;
end
corn = [x,y;x,y+l;x+l,y;x+l,y+l]';
% figure;imshow(b>0); hold on;
% plot(corn(1,:),corn(2,:),'O')
return;
end
The black boundaries in your image are curved and not closed. For example, in the top right corner, the black boundaries won't meet and form a closed contour. Therefore, a simple strategy in one of my comments will not work.
I am now providing you with a skeleton of a code which you can play with and add conditions as per your need. My idea is as follows:
To find left-side x-coordinate of the rectangle, first count the white pixels each column of the image contains:
%I assume that the image has already been converted to binary.
whitePixels=sum(img,1);
Then find the rate of change:
diffWhitePixels=diff(whitePixels);
If you see the bar plot of diffWhitePixels then you will observe various large entries (which indicate that the white region is still not in a straight line, and it is not a proper place to put the rectangles left vertical edge). Small entries (in your image, less than 5) indicate you can put the rectangle edge there.
You can do similar things to determine right, top and bottom edge positions of the rectangles.
Discussion:
First of all, the problem is ill-posed in my opinion. What do you mean by maximum-sized rectangle? Is it maximum area or length of side? In all possible cases, I don't think above method can get the correct answer. I can think of two or three cases right now where above method would fail, but it will at least give you the right answer on images similar to the given image, provided you adjust the values.
You can put some constraints once you know how your images are going to look. For example, if the black boundary curves inside, you can say that you don't want a column such as [0;0;...0;1;1;...0;0;...;0;1;1;...;1] i.e. zeros surrounded by ones. Another constraint could be how many black pixels do you want to allow? You can also crop the image till to remove extra black pixels. In your image, you can crop the image (programmatically) from the left and the bottom edge. Cropping an image is probably necessary, and definitely the better thing to do.
I'm making an image processing project and I have stuck in one the project's steps. Here is the situation;
This is my mask:
and I want to detect the maximum-sized rectangle that can fit into this mask like this.
I'm using MATLAB for my project. Do you know any fast way to accomplish this aim. Any code sample, approach or technique would be great.
EDIT 1 : The two algorithms below are works with lot's of the cases. But both of them give wrong results in some difficult cases. I'am using both of them in my project.
This approach starts with the entire image and shrinks each border in turn pixel-by-pixel until it finds an acceptable rectangle.
It takes ~0.02 seconds to run on the example image, so it's reasonably fast.
EDIT: I should clarify that this isn't meant to be a universal solution. This algorithm relies on the rectangle being centered and having roughly the same aspect ratio as the image itself. However, in the cases where it is appropriate, it is fast. #DanielHsH offered a solution which they claim works in all cases.
The code:
clear; clc;
tic;
%% // read image
imrgb= imread('box.png');
im = im2bw(rgb2gray(imrgb)); %// binarize image
im = 1-im; %// convert "empty" regions to 0 intensity
[rows,cols] = size(im);
%% // set up initial parameters
ULrow = 1; %// upper-left row (param #1)
ULcol = 1; %// upper-left column (param #2)
BRrow = rows; %// bottom-right row (param #3)
BRcol = cols; %// bottom-right column (param #4)
parameters = 1:4; %// parameters left to be updated
pidx = 0; %// index of parameter currently being updated
%% // shrink region until acceptable
while ~isempty(parameters); %// update until all parameters reach bounds
%// 1. update parameter number
pidx = pidx+1;
pidx = mod( pidx-1, length(parameters) ) + 1;
p = parameters(pidx); %// current parameter number
%// 2. update current parameter
if p==1; ULrow = ULrow+1; end;
if p==2; ULcol = ULcol+1; end;
if p==3; BRrow = BRrow-1; end;
if p==4; BRcol = BRcol-1; end;
%// 3. grab newest part of region (row or column)
if p==1; region = im(ULrow,ULcol:BRcol); end;
if p==2; region = im(ULrow:BRrow,ULcol); end;
if p==3; region = im(BRrow,ULcol:BRcol); end;
if p==4; region = im(ULrow:BRrow,BRcol); end;
%// 4. if the new region has only zeros, stop shrinking the current parameter
if isempty(find(region,1))
parameters(pidx) = [];
end
end
toc;
params = [ULrow ULcol BRrow BRcol]
area = (BRrow-ULrow)*(BRcol-ULcol)
The results for this image:
Elapsed time is 0.027032 seconds.
params =
10 25 457 471
area =
199362
Code to visualize results:
imrgb(params(1):params(3),params(2):params(4),1) = 0;
imrgb(params(1):params(3),params(2):params(4),2) = 255;
imrgb(params(1):params(3),params(2):params(4),3) = 255;
imshow(imrgb);
Another example image:
Here is a correct answer.
You must use dynamic programming! Other methods of direct calculation (like cutting 1 pixel from each edge) might produce sub-optimal results. My method guarantees that it selects the largest possible rectangle that fits in the mask. I assume that the mask has 1 big convex white blob of any shape with black background around it.
I wrote 2 methods. findRect() which finds the best possible square (starting on x,y with length l). The second method LargestInscribedImage() is an example of how to find any rectangle (of any aspect ratio). The trick is to resize the mask image, find a square and resize it back.
In my example the method finds the larges rectangle that can be fit in the mask having the same aspect ration as the mask image. For example if the mask image is of size 100x200 pixels than the algorithm will find the largest rectangle having aspect ratio 1:2.
% ----------------------------------------------------------
function LargestInscribedImage()
% ----------------------------------------------------------
close all
im = double(imread('aa.bmp')); % Balck and white image of your mask
im = im(:,:,1); % If it is colored RGB take only one of the channels
b = imresize(im,[size(im,1) size(im,1)]); Make the mask square by resizing it by its aspect ratio.
SC = 1; % Put 2..4 to scale down the image an speed up the algorithm
[x1,y1,l1] = findRect(b,SC); % Lunch the dyn prog algorithm
[x2,y2,l2] = findRect(rot90(b),SC); % rotate the image by 90deg and solve
% Rotate back: x2,y2 according to rot90
tmp = x2;
x2 = size(im,1)/SC-y2-l2;
y2 = tmp;
% Select the best solution of the above (for the original image and for the rotated by 90degrees
if (l1>=l2)
corn = sqCorn(x1,y1,l1);
else
corn = sqCorn(x2,y2,l2);
end
b = imresize(b,1/SC);
figure;imshow(b>0); hold on;
plot(corn(1,:),corn(2,:),'O')
corn = corn*SC;
corn(1,:) = corn(1,:)*size(im,2)/size(im,1);
figure;imshow(im); hold on;
plot(corn(1,:),corn(2,:),'O')
end
function corn = sqCorn(x,y,l)
corn = [x,y;x,y+l;x+l,y;x+l,y+l]';
end
% ----------------------------------------------------------
function [x,y,l] = findRect(b,SC)
b = imresize(b,1/SC);
res = zeros(size(b,1),size(b,2),3);
% initialize first col
for i = 1:1:size(b,1)
if (b(i,1) > 0)
res(i,1,:) = [i,1,0];
end
end
% initialize first row
for i = 1:1:size(b,2)
if (b(1,i) > 0)
res(1,i,:) = [1,i,0];
end
end
% DynProg
for i = 2:1:size(b,1)
for j = 2:1:size(b,2)
isWhite = b(i,j) > 0;
if (~isWhite)
res(i,j,:)=res(i-1,j-1,:); % copy
else
if (b(i-1,j-1)>0) % continuous line
lineBeg = [res(i-1,j-1,1),res(i-1,j-1,2)];
lineLenght = res(i-1,j-1,3);
if ((b(lineBeg(1),j)>0)&&(b(i,lineBeg(2))>0)) % if second diag is good
res(i,j,:) = [lineBeg,lineLenght+1];
else
res(i,j,:)=res(i-1,j-1,:); % copy since line has ended
end
else
res(i,j,:) = [i,j,0]; % Line start
end
end
end
end
% check last col
[maxValCol,WhereCol] = max(res(:,end,3));
% check last row
[maxValRow,WhereRow] = max(res(end,:,3));
% Find max
x= 0; y = 0; l = 0;
if (maxValCol>maxValRow)
y = res(WhereCol,end,1);
x = res(WhereCol,end,2);
l = maxValCol;
else
y = res(end,WhereRow,1);
x = res(end,WhereRow,2);
l = maxValRow;
end
corn = [x,y;x,y+l;x+l,y;x+l,y+l]';
% figure;imshow(b>0); hold on;
% plot(corn(1,:),corn(2,:),'O')
return;
end
The black boundaries in your image are curved and not closed. For example, in the top right corner, the black boundaries won't meet and form a closed contour. Therefore, a simple strategy in one of my comments will not work.
I am now providing you with a skeleton of a code which you can play with and add conditions as per your need. My idea is as follows:
To find left-side x-coordinate of the rectangle, first count the white pixels each column of the image contains:
%I assume that the image has already been converted to binary.
whitePixels=sum(img,1);
Then find the rate of change:
diffWhitePixels=diff(whitePixels);
If you see the bar plot of diffWhitePixels then you will observe various large entries (which indicate that the white region is still not in a straight line, and it is not a proper place to put the rectangles left vertical edge). Small entries (in your image, less than 5) indicate you can put the rectangle edge there.
You can do similar things to determine right, top and bottom edge positions of the rectangles.
Discussion:
First of all, the problem is ill-posed in my opinion. What do you mean by maximum-sized rectangle? Is it maximum area or length of side? In all possible cases, I don't think above method can get the correct answer. I can think of two or three cases right now where above method would fail, but it will at least give you the right answer on images similar to the given image, provided you adjust the values.
You can put some constraints once you know how your images are going to look. For example, if the black boundary curves inside, you can say that you don't want a column such as [0;0;...0;1;1;...0;0;...;0;1;1;...;1] i.e. zeros surrounded by ones. Another constraint could be how many black pixels do you want to allow? You can also crop the image till to remove extra black pixels. In your image, you can crop the image (programmatically) from the left and the bottom edge. Cropping an image is probably necessary, and definitely the better thing to do.
I'm trying to read the values in this image into variables using OCR in MATLAB. I'm having trouble doing so, so I tried to split up this image into smaller parts using the white boundary lines then trying to read it, but I dont know how to do this. Any help would be appreciated, thanks.
If the blocks are always delimited by a completely vertical line, you can find where they are by comparing the original image (here transformed from RGB to grayscale to be a single plane) to a matrix that is made of repeats of the first row of the original image only. Since the lines are vertical the intensity of the pixels in the first line will be the same throughout. This generates a binary mask that can be used in conjunction with a quick thresholding to reject those lines that are all black pixels in every row. Then invert this mask and use regionprops to locate the bounding box of each region. Then you can pull these out and do what you like.
If the lines dividing the blocks of text are not always vertical or constant intensity throughout then there's a bit more work that needs to be done to locate the dividing lines, but nothing that's impossible. Some example data would be good to have in that case, though.
img = imread('http://puu.sh/cU3Nj/b020b60f0b.png');
imshow(img);
imgGray = rgb2gray(img);
imgMatch = imgGray == repmat(imgGray(1,:), size(imgGray, 1), 1);
whiteLines = imgMatch & (imgGray > 0);
boxes = regionprops(~whiteLines, 'BoundingBox');
for k = 1:6
subplot(3,2,k)
boxHere = round(boxes(k).BoundingBox);
imshow(img(boxHere(2):(boxHere(2)+boxHere(4)-1), boxHere(1):(boxHere(1)+boxHere(3)-1), :));
end
You can sum along the columns of a binary image corresponding to that input image and find peaks from the sum values. This is precisely achieved in the code here -
img = imread('http://puu.sh/cU3Nj/b020b60f0b.png');
BW = im2bw(img,0.1); %// convert to a binary image with a low threshold
peak_sum_max = 30; %// max of sum of cols to act as threshold to decide as peak
peaks_min_width = 10; %// min distance between peaks i.e. min width of each part
idx = find( sum(BW,1)>=peak_sum_max );
split_idx = [1 idx( [true diff(idx)>peaks_min_width ] )];
split_imgs = arrayfun(#(x) img(:,split_idx(x):split_idx(x+1)),...
1:numel(split_idx)-1,'Uni',0);
%// Display split images
for iter = 1:numel(split_imgs)
figure,imshow(split_imgs{iter})
end
Please note that the final output split_imgs is a cell array with each cell holding image data for each split image.
If you would like to have the split images directly without the need for messing with cell arrays, after you have split_idx, you can do this -
%// Get and display split images
for iter = 1:numel(split_idx)-1
split_img = img(:,split_idx(iter):split_idx(iter+1));
figure,imshow(split_img)
end
There is now a built-in ocr function in the Computer Vision System Toolbox.
I have an image and my aim is to get whole line which is shown with red line. I am working with matlab and I don't want to use IM2 = imdilate(IM,SE) function.
Is there any function or method to do that?
The image:
Note: Sorry for bad red line. I drew it with paint.
Edit:
The original image is below:
Here's what I have after using imdilate at an intermediate step -
%// Read in image and convert to a binary one
im = imread('Line.jpg');
bw = im2bw(im);
%// There seems to be a thin white boundary across the image, make it false(black)
bw1 = false(size(bw));
bw1(5:end-5,5:end-5) = bw(5:end-5,5:end-5);
bw1(biggest_blob(bw1)) = 0; %// remove biggest blob (bottom left corner one)
SE = strel('disk', 11, 8); %// structuring element for dilation
bw2 = imdilate(bw1,SE); %// dilate the image
bw3 = bwmorph(bw2,'thin',Inf); %// thin it
out = biggest_blob(bw3); %// out of many thinned lines, select the biggest one
Please remember that the motive behind removing the biggest blob at the start of the codes is that without that being removed, we would have gotten the biggest blob being attached to the island blobs that we were trying to connect/combine and thus would have messed up the desired output.
Associated function (taken from Select largest object in an image) -
function out = biggest_blob(BW)
%// Find and labels blobs in the binary image BW
[L, num] = bwlabel(BW, 8);
%// Count of pixels in each blob, basically this should give the area of each blob
counts = sum(bsxfun(#eq,L(:),1:num));
%// Get the label(ind) cooresponding to blob with the maximum area
%// which would be the biggest blob
[~,ind] = max(counts);
%// Get only the logical mask of the biggest blob by comparing all labels
%// to the label(ind) of the biggest blob
out = (L==ind);
return;
Result -