Detecting specific lines using hough transform/houghlines in matlab - matlab

I am currently doing a matlab project where I must isolate a barcode from a image and read the barcode information.
The method that I am using is the Hough Transform, once the transform has completed I am using houghpeaks and houghlines so that I can determine the distance between each of the lines on the barcode. My image may be horizontal or vertical.
The problem that I am having is with the houghpeak detection and the houghline plotting. When I have a image that has vertical lines it is not detecting every line of the barcode. I have a link below of a barcode image that I am plotting lines onto, I would like for every vertical line over my specified length(65 in the case of this image) to have a line superimposed on it so that I can then take this information and measure the distance between each line
My reason for choosing 65 as my 'MinLength' is because I am getting horizontal lines plotted in other parts of the image if I dont specify this high value.
I have tried to implement sobel edge detection so that I could specify horizontal/vertical direction but get a error using it: ('Reference to non-existent field 'point1').
I am also not too clear on the 'FillGap' parameter, I have read the matlab help on it but I am still not getting my head around it. I have played around with different values to try and gain a understanding of it but I am not too clear.
I have also tried to implement the code using a image that has more than just a barcode.
In this image it is also only picking up what seems to be random houghpeaks and therefore not plotting the hough lines that I would like it to.
So my question is really can anybody tell me why the code is not plotting all of the hough lines on each 'line' of the barcode in the image.
Below is the code.
Thanks in advance!
I = imread('barcode (2).jpg');
I = im2double(I);
I = rgb2gray(I);
BW = edge(I,'canny');
[H,T,R] = hough(BW);
figure(1),imshow(H,[],'XData',T,'YData',R,'InitialMagnification','fit');
xlabel('\theta'), ylabel('\rho');
axis on, axis normal, hold on;
P = houghpeaks(H,26,'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',65);
figure, 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','cyan');

Instead of doing line detection to compute your barcode, why don't you plot a profile through the entire length of the barcode. This way you can detect peaks and troughs to distinguish black and white sections.
You would need way less computing power and your code would be much easier.

Related

How to Plot lines on image by 45 degrees from centroid. I have fitted a bounding box on image and found centroid

I have fitted a bounding box on image which have concerned area is human silhouette in BW, and found centroid according to concerned human silhouette?
now i have to plot red line by 45 degree angle from centroid.
from centroid to vertical, horizental and diagonal logic? Need code in MATLAB?
I have fitted a bounding box on image and found centroid according to concerned human silhouette?
% bounding box
labeledImage = bwlabel(Ibw);
blobMeasurements = regionprops(labeledImage, 'BoundingBox');
thisBlobsBoundingBox = blobMeasurements.BoundingBox;
subImage = imcrop(Ibw, thisBlobsBoundingBox);
figure, imshow(subImage);
imwrite(subImage,fullfile(cd, strcat('Croped By BoundingBox','.png')));
%centroid
Ibw = imread('Croped By BoundingBox.png');
Ibw = imfill(Ibw,'holes');
Ilabel = bwlabel(Ibw);
stat = regionprops(Ilabel,'centroid');
imshow(Ibw),hold on;
for x = 1: numel(stat)
plot(stat(x).Centroid(1),stat(x).Centroid(2),'ro');
[rows, cols] =ndgrid(1:size(Ibw, 1), 1:size(Ibw, 2));
centroidrowcol = mean([rows(:) .* Ibw(:), cols(:) .* Ibw(:)]);
hold on
end
figure, imshow(Ibw);
imwrite(Ibw,fullfile(cd, strcat('Centroid','.png')));
plot lines from centroid to vercally horizentally and diagonally by 45 degree from centroid.
i have to obtaon these results
enter image description here
I'll start with assuming centroid, a length-2 vector, is the coordinates of a centroid -- since you already have them.
As a reminder, 45 degree lines centered at (0,0) are the images of the functions f(x)=x and f(x)=-x. In order to shift the lines to intercept points of your choice, say (x0, y0), you need f(x-x0)+y0. In other words, f(x)=x-x0+y0 and f(x)=-x+x0+y0 respectively.
Knowing the functions (whose images are) the lines of your desire, there are a number of things you can do in order to complete the task. You can define Matlab functions as such and plot the usual way with plot, or for a quick display, with ezplot:
ezplot(#(x)x-centroid(1)+centroid(2));
line() in Matlab allows you to draw a line segment between two points in 2D, among other things. With line(), you actually don't have to know the equations explicitly. You just need two points. So, one possibility is that you use [centroid(1)+1, centroid(2)+1] as your first point and [centroid(1)-1, centroid(2)-1] as your second point for the shifted f(x)=x line.
Just read the documentation for the correct syntax. In the above example, you would put in
line([centroid(1)+1;centroid(1)-1], [centroid(2)+1;centroid(2)-1]);
This draws a 45 degree line segment alright. You also want the length of the line segment to be visually sensible. You can either autoscale the length, ie. change the 1 into a formula, based on the size of your image. OR, you can make sure your segment is longer than the extent of the image but confine your plot to a certain size by changing xlim and ylim.

General approach for extracting specific lines or line segments in an image

I have this sample cropped image:
I need to make black thick lines (horizontal and vertical) disappear or extracted while leave all other info intact. These specific lines are either 4 or 5 pixels thick. I tried:
Simple filtering of rows having more zeros/ones if image is read as NumPy array but the filtering condition doesn't terminate till a single row is left with zero or one.
Erosion with simple kernel (3,3) but it leaves some noise because some symbols are also thick black
Dilation with line structuring element of the width of image width but there are overwhelming variations on line segments' sizes connecting different symbols that the basic info about each small line segment is lost.
Can someone give insights or directions about what kind of structuring elements, what type of morphological ops should be considered or may be any other clever heuristics? The output, if extraction of thick black lines is done, will then look like this grid of random line segments:
This is how you erode the image and extract hough lines:
I=rgb2gray(imread('https://i.stack.imgur.com/cbHFL.jpg'));
Ibw=I>200;
imshow(Ibw)
SE=strel('disk',1)
Ier=imerode(~Ibw,SE);
[H,T,R] = hough(Ier);
P = houghpeaks(H,100,'threshold',ceil(0.1*max(H(:))));
lines = houghlines(Ier,T,R,P);
%% plot
imshow(I);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','blue');
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
From here, you can start thinking on what to delete. This is not straightforward unless you have a dictionary of symbols, e.g. how do you delete the line around the structures with >-< shape? do you delete all the middle pixels or do you keep the entire middle thin bar? You can only know this if you know how the symbol should be without the thick lines.

Detect parallel lines using Hough transform in matlab

Suppose there is a binary image of a black background and white lines "plotted" on it, i.e., they aren't burnt onto the image. For example:
I need to retain only the lines that are parallel to atleast one of the other lines in the picture. If not perfectly parallel, at least close enough to be parallel(perhaps a variable that can control the degree of parallelism would help with that). In other words, if I choose a particular line and it has one or more lines that are parallel to it, I retain it, else I discard it. I need to do that for all lines in the image.
I came across Hough transform but I'm having trouble understanding how to use the bins to check the orientations and determine parallel lines. Or is there a better way to go about this?
Also, since the lines aren't a part of the image and are just plotted on it, I don't have an image to feed into the Hough Transform function. Can I use the output of the plot function as input directly? This is the code I wrote to plot the white lines:
Location1 is a m-by-2 matrix that contains the coordinates to draw the lines.
figure; imshow(blackImage);
hold on ;
for i=1:size(Location1,1)-1
h = plot([Location1(i,1) Location1(i+1,1)], [Location1(i,2) Location1(i+1,2)]) ;
set(h,'linewidth', .1, 'color', 'b') ;
end
Any help would be appreciated.
Given that
for i=1:size(Location1,1)-1
% one line = Location1(i,:) to Location1(i+1,:)
end
then
theta = atan2(diff(Location1(:,2)),diff(Location1(:,1)));
But since lines are parallel even if their theta is in the opposite direction, you want to map all angles to half a circle:
theta = mod(theta,pi/2);
Now theta is in the range [-π/2,π/2].
To find similar angles:
[s,i] = sort(theta);
k = find(diff(s)<0.01); % diff(s) is always positive because s is sorted
i = i([k,k+1]);
theta(i) % <-- sets of similar angles
% Location1(i,:),Location1(i+1,:) <- corresponding lines

Find the intersections of a series of curves of an image: Matlab

I have an image with a series of lines, like below:
I would like to know if there is some method for finding the intersections of all of the lines.
I was checking another post where they offer a way to find the intersections, but once the image is segmented I suppose it has noise or something similar... I will start with a simple image to find each intersection.
My main idea was to solve the "system of equations" but I think for an image with many intersections would be too difficult, I do not know if there is any method to find all intersections.
I assume you don't have the line equations. I used skeletonization and filtering to detect small areas with more than one line crossing them. I'm not sure that it will be so simple for noisy image but it worth trying:
im = im2double(rgb2gray(imread('lines.png')));
% binarize black lines
bw = im == 0;
% skelatonize lines
sk = bwmorph(bw,'skel',inf);
% filter skeleton with 3X3 ones filter
A = imfilter(double(sk),ones(3));
% find blobs greater than 4 - more than one line crossing the filter
B = A > 4;
% get centroids of detected blobs
C = regionprops(B,'Centroid');
Cent = reshape([C.Centroid],2,[]).';
% plot
imshow(im)
hold on;
plot(Cent(:,1),Cent(:,2),'gx','LineWidth',2)

Extract Individual Line Segment Coordinates from Boundary Image - MATLAB

I have a MATLAB script that gives me the boundary lines of an image using bwboundaries().
Now, after plotting that image, I am getting the complete image, formed from various straight line segments.
I would like to get the coordinates or show the individual line segments that form the boundary.
I think the method is called digital straightness of lines, but I want to know how to apply it here in this case.
[B,L,N] = bwboundaries(z,'noholes');
for k=1:length(B),
boundary = B{k};
if(k > N)
figure, plot(boundary(:,2),boundary(:,1),'g','LineWidth',2);
else
figure, plot(boundary(:,2),boundary(:,1),'r','LineWidth',2);
end
end
According to my understanding of your question,my idea is to use bwtraceboundary().
BW = imread('image.png');
imshow(BW,[]);
r = 165; % you can get the r and c for your image using "impixelinfo"
c = 43;
contour = bwtraceboundary(BW,[r c],'W',4,Inf,'counterclockwise');
hold on;
plot(contour(:,2),contour(:,1),'g','LineWidth',2);
x=contour(:,2)'
y=contour(:,2)'
Am I answering your question?
Use regionprops('desired feature') on the labelled image.
To generate a labelled image use
bwlabel(Img) (high memory usage)
or
bw=bwconncomp(Img,conn) (low memory use)
followed by
labelmatrix(bw)
The best way to proceed would probably be to use a Hough Transform to first get an idea of the lines present in the image. You can play around with Hough Transform to extract the end points of the lines.