Discarding everything above a slanted line in an image - image

I am trying to discard (i.e. zero out) all of the pixels above a certain region in an image (for example, a clearly defined white bar). Is there any way I can use the result of a Sobel edge detection to accomplish this, or is there a better way?

You could try something like this:
I = imread('image.png'); % read image
E = edge(I) % get results of canny edge detector
[~,idx] = max( sum(E,2:) ); % find the row with the clearest horizontal edge
I(1:idx-1,:) = 0; % zero everything above (not including) that row
You could probably replace the canny edge image with a Sobel image and get the same results.

Related

How to detect a portion of an image based upon the matrix values?

I have a simple pcolor plot in Matlab (Version R 2016b) which I have uploaded as shown in the image below. I need to get only the blue sloped line which extends from the middle of the leftmost corner to the rightmost corner without hard-coding the matrix values.
For instance: One can see that the desired slope line has values somewhere approximately between 20 to 45 from the pcolor plot. (From a rough guess just by looking at the graph)
I'm applying the following code on the matrix named Slant which contains the plotted values.
load('Slant.mat');
Slant(Slant<20|Slant>50)=0;
pcolor(Slant); colormap(jet); shading interp; colorbar;
As one can see I hard-coded the values which I don't want to. Is there any method of detecting certain matrix values while making the rest equal to zero?
I used an other small algorithm of taking half the maximum value from the matrix and setting it to zero. But this doesn't work for other images.
[maxvalue, row] = max(Slant);
max_m=max(maxvalue);
Slant(Slant>max_m/2)=0;
pcolor(Slant); colormap(jet); shading interp; colorbar;
Here is another suggestion:
Remove all the background.
Assuming this "line" results in a Bimodal distribution of the data (after removing the zeros), find the lower mode.
Assuming the values of the line are always lower than the background, apply a logic mask that set to zeros all values above the minimum + 2nd_mode, as demonstrated in the figure below (in red circle):
Here is how it works:
A = Slant(any(Slant,2),:); % save in A only the nonzero data
Now we have A that looks like this:
[y,x] = findpeaks(histcounts(A)); % find all the mode in the histogram of A
sorted_x = sortrows([x.' y.'],-2); % sort them by their hight in decendet order
mA = A<min(A(:))+sorted_x(2,1); % mask all values above the second mode
result = A.*mA; % apply the mask on A
And we get the result:
The resulted line has some holes within it, so you might want to interpolate the whole line from the result. This can be done with simple math on the indices:
[y1,x1] = find(mA,1); % find the first nonzero row
[y2,x2] = find(mA,1,'last'); % find the last nonzero row
m = (y1-y2)/(x1-x2); % the line slope
n = y1-m*x1; % the intercept
f_line = #(x) m.*x+n; % the line function
So we get a line function f_line like this (in red below):
Now we want to make this line thicker, like the line in the data, so we take the mode of the thickness (by counting the values in each column, you might want to take max instead), and 'expand' the line by half of this factor to both sides:
thick = mode(sum(mA)); % mode thickness of the line
tmp = (1:thick)-ceil(thick/2); % helper vector for expanding
rows = bsxfun(#plus,tmp.',floor(f_line(1:size(A,2)))); % all the rows for each coloumn
rows(rows<1) = 1; % make sure to not get out of range
rows(rows>size(A,1)) = size(A,1); % make sure to not get out of range
inds = sub2ind(size(A),rows,repmat(1:size(A,2),thick,1)); % convert to linear indecies
mA(inds) = 1; % add the interpolation to the mask
result = A.*mA; % apply the mask on A
And now result looks like this:
Idea: Use the Hough transform:
First of all it is best to create a new matrix with only the rows and columns we are interested in.
In order to apply matlab's built in hough we have to create a binary image: As the line always has lower values than the rest, we could e.g. determine the lowest quartile of the brightnesses present in the picture (using quantile, and set these to white, everything else to black.
Then to find the line, we can use hough directly on that BW image.

Remove noise from characters in an image

I processed my input image and the result is below. I just need the characters. I tried but can't remove the noise surrounding the characters.
A simple erosion with a small structuring element, like a 3 x 3 square may work where you would eliminate the small white noise profile and thus make the characters darker. You can also take advantage of the fact that the areas that are black that are not characters are connected to the boundaries of the image. You can remove these from the image by removing areas connected to the boundaries.
Therefore, perform an erosion first using imerode, then you will need to remove the boundaries using imclearborder but this requires that the pixels touching the border are white. Therefore, use the inverse of the output from imerode into the function, then inverse it again.
Something like this will work and I'll read your image from Stack Overflow directly:
% Read the image and threshold in case
im = imread('https://i.stack.imgur.com/Hl6Y9.jpg');
im = im > 200;
% Erode
out = imerode(im, strel('square', 3));
% Remove the border and find inverse
out = ~imclearborder(~out);
We get this image now:
There are some isolated black holes near the B that you may not want. You can do some additional post-processing by using bwareaopen to remove islands that are below a certain area. I chose this to be 50 pixels from experimentation. You'll have to do this on the inverse of the output from imclearborder:
% Read the image and threshold in case
im = imread('https://i.stack.imgur.com/Hl6Y9.jpg');
im = im > 200;
% Erode
out = imerode(im, strel('square', 3));
% Remove the border
bor = imclearborder(~out);
% Remove small areas and inverse
out = ~bwareaopen(bor, 50);
We now get this:

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);

Counting number of edge pixels in matlab

I want to count the number of edge pixels in a given image. I tried it by counting pixels of white color of the image we get by using Canny operator on the image.
I = rgb2gray(imread('replay1.jpg'));
bw = edge(I,'canny');
numberOfBins = 256;
[r, cl, x] = size(bw);
[pixelCount, grayLevels] = imhist(bw);
c = sum(pixelCount(pixelCount==255));
disp(c*100/(r*cl));
Questions:
1. But this somehow gives the same answer for all images, which suggests I am doing it wrong. How should I find number of edge pixels of an image in matlab?
2. Also can I use canny operator on YCbCr format of an image? I tried doing that but it gives me errors.
PART 1
Use this - count_edge_pixels = nnz(bw) This is a very efficient way to calculate true (1) values that are edge pixels in this case and thus, would give you count of edge/white pixels as calculated from edge.
PART 2
You can use edge on each of Y, Cb, Cr separately or just use Y for edge detection on the luminance part. Use this to get YCbCr from RGB images.
Let's suppose you would like to get edge information on the luminance map of the image, do something like this -
YCBCR = rgb2ycbcr(imread('replay1.jpg'));
luminance_map = YCBCR(:,:,1);
bw = edge(luminance_map,'canny');
Hope this makes sense and works for you!
pixelCount(2) will give you the number of edge pixels here. As #Divakar mentioned, nnz(bw) will also work as expected.
I = rgb2gray(imread('test.jpg'));
bw = edge(I,'canny');
numberOfBins = 256;
[r, cl, x] = size(bw);
[pixelCount, grayLevels] = imhist(bw);
count = pixelCount(2); // <- here, or use "count = nnz(bw)"
To detect canny edges on YCbCr images, you can use edgecolor.m.
This is also efficient way to count the num of edge pixels.
count =length(find(BW(:)==1));

Resources