How to remove horizontal and vertical lines - matlab

I need to remove horizontal and vertical lines in a binary image. Is there any method for filtering these lines? bwareaopen() is not good method to remove these lines and also Dilation and Erosion are not good for these cases.
Does any one know a solution?
Example image:
EDIT:(added more example images:
http://s1.upload7.ir/downloads/pPqTDnmsmjHUGTEpbwnksf3uUkzncDwr/example%202.png
source file of images:
https://www.dropbox.com/sh/tamcdqk244ktoyp/AAAuxkmYgBkB8erNS9SajkGVa?dl=0
www.directexe.com/9cg/pics.rar

Use regionprops and remove regions with high eccentricity (meaning the region is long and thin) and orientation near 0 or near 90 degrees (regions which are vertical or horizontal).
Code:
img = im2double(rgb2gray(imread('removelines.jpg')));
mask = ~im2bw(img);
rp = regionprops(mask, 'PixelIdxList', 'Eccentricity', 'Orientation');
% Get high eccentricity and orientations at 90 and 0 degrees
rp = rp([rp.Eccentricity] > 0.95 & (abs([rp.Orientation]) < 2 | abs([rp.Orientation]) > 88));
mask(vertcat(rp.PixelIdxList)) = false;
imshow(mask);
Output:

If all of your images are the same where the horizontal and vertical lines are touching the border, a simple call to imclearborder will do the trick. imclearborder removes any object pixels that are touching the borders of the image. You'll need to invert the image so that the characters are white and the background is dark, then reinvert back, but I'm assuming that isn't an issue. However, to be sure that none of the actual characters get removed because they may also be touching the border, it may be prudent to artificially pad the top border of the image with a single pixel thickness, clear the border, then recrop.
im = imread('http://i.stack.imgur.com/L1hUa.jpg'); %// Read image directly from StackOverflow
im = ~im2bw(im); %// Convert to black and white and invert
im_pad = zeros(size(im,1)+1, size(im,2)) == 1; %// Pad the image too with a single pixel border
im_pad(2:end,:) = im;
out = ~imclearborder(im_pad); %// Clear border pixels then reinvert
out = out(2:end,:); %// Crop out padded pixels
imshow(out); %// Show image
We get this:

You can firstly find the horizontal and vertical lines. Since, the edge map will also be binary so you can perform a logical subtraction operation in between the images. To find vertical lines, you can use (in MATLAB)
BW = edge(I,'sobel','vertical');
For horizontal lines, you can use
% Generate horizontal edge emphasis kernel
h = fspecial('sobel');
% invert kernel to detect vertical edges
h = h';
J = imfilter(I,h);

Related

How to remove white annotations from image?

I try to remove the white annotations of this image (the numbers and arrows), as well as the black grid, with MATLAB:
I tried to compute, for each pixel, the mode of neighbors, but this process is very slow and I get poor results.
How can I obtain an image like this one?
Thank you for your time.
The general name for such a task is inpainting. If you search for that you will find better methods than what I'm showing here. This is no more than a proof of concept. I'm using DIPimage 3 (because I'm an author and it's easy for me to use).
First we need to create a mask for the regions that we want to remove (inpaint). It is easy to find pixels where all three channels have a high value (white) or a low value (black):
img = readim('https://i.stack.imgur.com/16r9N.png');
% Find a mask for the areas to remove
whitemask = min(img,'tensor') > 50;
blackmask = max(img,'tensor') < 30;
mask = whitemask | blackmask;
This mask doesn't capture all of the black grid, if we increase the threshold we will also remove the dark region of sea off the coast of Spain. And it also captures the white outline of the coasts. We can do a little bit better than this with some additional filtering:
% Find a mask for the areas to remove
whitemask = min(img,'tensor') > 50;
whitemask = whitemask - pathopening(whitemask,50);
blackmask = max(img,'tensor');
blackmask2 = blackmask < 80;
blackmask2 = blackmask2 - areaopening(blackmask2,6);
blackmask = blackmask < 30 | blackmask2;
mask = whitemask | blackmask;
This produces the following mask:
Still far from perfect, but a good start for our proof of concept.
One simple inpainting method uses normalized convolution: using the inverse of the mask we made, convolve the image multiplied by the mask, and convolve the mask separately. The ratio of these two results is a smoothed image that doesn't take the masked pixels into account. Finally, we replace the pixels in the original image under the mask with the values from this normalized convolution:
% Solution 1: normalized convolution
smooth = gaussf(img * ~mask, 2) / gaussf(~mask, 2);
img(mask) = smooth(mask);
An alternative solution applies a closing on the image multiplied by the mask (note that this multiplication makes the pixels we don't want completely black; the closing will spread the surrounding colors over the black areas):
% Solution 2: morphology
smooth = iterate('closing',img * ~mask, 13);
img(mask) = smooth(mask);

Finding area in image with maximum variation of pixels

I am struggling with some algorithm to extract the region from an image which has the maximum change in pixels. I got the following image after preprocessing.
I did following steps of pre-processing
x = imread('test2.jpg');
gray_x = rgb2gray(x);
I = medfilt2(gray_x,[3 3]);
gray_x = I;
%%
canny_x = edge(gray_x,'canny',0.3);
figure,imshow(canny_x);
%%
s = strel('disk',3);
si = imdilate(canny_x,s);
%figure5
figure; imshow(si);
se = imerode(canny_x,s);title('dilation');
%figure6
figure; imshow(se);title('Erodsion');
I = imsubtract(si,se);
%figure7
figure; imshow(I);
Basically what I am struggling for, is to make weapon detection system using Image processing. I want to localize possible area's to be weapon so that I could feed them to my classifier to identify if it is a weapon or not. Any suggestions? Thank you
A possible solution could be:
Find corner points in the image (Harris corner points, etc)
Set value of all the corner points to white while remaining image will be black
Take a rectangular window and traverse it over the whole image
sum all the white pixels in that rectangular window
select that region whose sum is maximum of all regions

Matlab - rotate a card [duplicate]

This question already has answers here:
How to straighten a tilted square shape in an image?
(2 answers)
Closed 5 years ago.
I have a cropped image of a card:
The card is a rectangle with rounded corners, is brightly colored, and sits on a relatively dark background.
It is, therefore, easy to differentiate between pixels belonging to the card and pixels belonging to the background.
I want to use MATLAB to rotate the card so its sides are vertical and horizontal (and not diagonal) and create an image of nothing but the straightened card.
I need this to work for any reasonable card angle (say +45 to -45 degrees of initial card rotation).
What would be the best way of doing this?
Thanks!
You can do this by finding the lines made by the edges of the card. The angle of rotation is then the angle between one of the lines and the horizontal (or vertical).
In MATLAB, you can use the Hough line detector to find lines in a binary image.
0. Read the input image
I downloaded your image and renamed it card.png.
A = imread('card.png');
We don't need color information, so convert to grayscale.
I = rgb2gray(A);
1. Detect edges in the image
A simple way is to use the Canny edge detector. Adjust the threshold to reject noise and weak edges.
BW = edge(I, 'canny', 0.5);
Display the detected edges.
figure
imshow(BW)
title('Canny edges')
2. Use the Hough line detector
First, you need to use the Hough transform on the black and white image, with the hough function. Adjust the resolution so that you detect all lines you need later.
[H,T,R] = hough(BW, 'RhoResolution', 2);
Second, find the strongest lines in the image by finding peaks in the Hough transform with houghpeaks.
P = houghpeaks(H, 100); % detect a maximum of 100 lines
Third, detect lines with houghlines.
lines = houghlines(BW, T, R, P);
Display the detected lines to make sure you find at least one along the edge of the card. The white border around the black background in your image makes detecting the right edges a bit more difficult.
figure
imshow(A)
hold on
for k = 1:length(lines)
xy = [lines(k).point1; lines(k).point2];
plot(xy(:,1), xy(:,2), 'LineWidth', 2, 'Color', 'red');
end
title('Detected lines')
3. Calculate the angle of rotation
lines(3) is the left vertical edge of the card. lines(3).point2 is the end of the line that is at the bottom. We want this point to stay where it is, but we want to vector along the line to be aligned with the vector v = [0 -1]'. (The origin is the top-left corner of the image, x is horizontal to the right and y is vertical down.)
lines(3)
ans =
struct with fields:
point1: [179 50]
point2: [86 455]
theta: 13
rho: 184
Simply calculate the angle between the vector u = lines(3).point1 - lines(3).point2 and the vertical vector v.
u = lines(3).point1 - lines(3).point2; % vector along the vertical left edge.
v = [0 -1]; % vector along the vertical, oriented up.
theta = acos( u*v' / (norm(u) * norm(v)) );
The angle is in radians.
4. Rotate
The imrotate function lets you rotate an image by specifying an angle in degrees. You could also use imwarp with a rotation transform.
B = imrotate(A, theta * 180 / pi);
Display the rotated image.
figure
imshow(B)
title('Rotated image')
Then you would have to crop it.

Finding the area of the black spots in a circle MATLAB

Is it possible to find the area of the black pixelation of an area within a circle? in other words I want to find the number of pixels (the area) of the RGB 0,0,0 (black pixels) within the circle. I do not want the areas of the white pixels (1,1,1) within the circle. I also have a radius of the circle if that helps. Here is the image:
Here is the code:
BW2= H(:,:) <0.45 ;%& V(:,:)<0.1;
aa=strel('disk',5);
closeBW = imclose(BW2,aa);
figure, imshow(closeBW)
imshow(closeBW)
viscircles([MYY1 MYX1], round(MYR2/2))
MYY1,MYX2, and the other values are calculated by my program. How can I find the area of the black pixelation in my circle?
Here is an idea:
1) Calculate the total # of black pixels in your original image (let's call it A).
2) Duplicate that image (let's call it B) and replace all pixels inside the circle with white. To do that, create a binary mask. (see below)
3) Calculate the total # of black pixels in that image (i.e. B).
4) Subtract both values. That should give you the number of black pixels within the circle.
Sample code: I used a dummy image I had on my computer and created a logical mask with the createMask method from imellipse. That seems complicated but in your case since you have the center position and radius of the circle you can create directly your mask like I did or by looking at this question/answer.
Once the mask is created, use find to get the linear indices of the white pixels of the mask (i.e. all of it) to replace the pixels in the circle of your original image with white pixels, which you use to calculate the difference in black pixels.
clc;clear;close all
A = im2bw(imread('TestCircle.png'));
imshow(A)
Center = [160 120];
Radius = 60;
%// In your case:
% Center = [MYY1 MYX1];
% Radius = round(MYR2/2);
%// Get sum in original image
TotalBlack_A = sum(sum(~A))
e = imellipse(gca, [Center(1) Center(2) Radius Radius]);
%// Create the mask
ROI = createMask(e);
%// Find white pixels
white_id = find(ROI);
%// Duplicate original image
B = A;
%// Replace only those pixels in the ROI with white
B(white_id) = 1;
%// Get new sum
NewBlack_B = sum(sum(~B))
%// Result!
BlackInRoi = TotalBlack_A - NewBlack_B
In this case I get this output:
TotalBlack_A =
158852
NewBlack_B =
156799
BlackInRoi =
2053
For this input image:

How to colour the edges after using sobel filter?

I am using sobel filter for edge detection. How to illustrate the gradient direction with color coding. For example, horizontal edges with blue and vertical edges with yellow?
Thank you.
Since you can specify whether you want horizontal or vertical edge detected (check here), you could perform 2 filtering operations (one horizontal and the other vertical) and save each resulting image, then concatenating them to form a final, 3-channels RGB image.
The RGB color code for yellow is [1 1 0] and that of blue is [0 0 1], so in your case the vertical edge image will occupy the first 2 channels whereas the horizontal edge image will occupy the last channel.
Example:
clear
clc
close all
A = imread('circuit.tif');
[r,c,~] = size(A);
EdgeH = edge(A,'Sobel','Horizontal');
EdgeV = edge(A,'Sobel','Vertical');
%// Arrange the binary images to form a RGB color image.
FinalIm = zeros(r,c,3,'uint8');
FinalIm(:,:,1) = 255*EdgeV;
FinalIm(:,:,2) = 255*EdgeV;
FinalIm(:,:,3) = 255*EdgeH;
figure;
subplot(1,2,1)
imshow(A)
subplot(1,2,2)
imshow(FinalIm)
Output: