Hough Transformation performes bad in detecting crop rows - hough-transform

I tried to detect crop rows in an image as: Original Image.
I first did some segmentation including ExGreen, Otsu tresholding, Morphological operations and canny edge detection: Segmentation.
I tried many different parameters, tresholds etc. in each step but the Hough Transform performes really bad: Hough Transform. I dont know how to choose the perfect rho, theta.. of the Hough Transform. Is there any way to calibrate the Ht, so it would only detect the four center lines? The values of rho, theta, treshold, minLineLenght and maxLineGap are definatly wrong down there, it´s just an example how i coded.
hough = cv2.HoughLinesP(Image, rho=1, theta=np.pi/180, threshold= 50, minLineLength= 100, maxLineGap= 5000)
line_image = np.zeros_like(Image)
if hough is not None:
for line in hough:
x1,y1,x2,y2 = line.reshape(4)
cv2.line(line_image, (x1,y1), (x2,y2), (255,0,0), 10)

Related

Counting homogeneous objects along the contour

I'm trying to get amount of objects on the frame by finding their contours with OpenCV.
That's a frame after Canny filter applying:
Then I call findContours() method and leave ones which suitable in size.
When I overlay them on a frame I've got
the following picture.
It can be seen that we've got only full contour objects.
So the question is:
How can we artificially make the boundaries of objects holistic?
I tried to use dilate and erode (result of that) but after that borders of objects are glued together and we can't find their contours any more.
Since the contours are connected together, findContours will detect the connected contours as a single contour instead of individual separated circles. When you have connected contours, a potential approach is to use Watershed to label and detect each contour. Here's the results:
Input image
Output
Code
import cv2
import numpy as np
from skimage.feature import peak_local_max
from skimage.morphology import watershed
from scipy import ndimage
# Load in image, convert to gray scale, and Otsu's threshold
image = cv2.imread('1.png')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1]
# Compute Euclidean distance from every binary pixel
# to the nearest zero pixel then find peaks
distance_map = ndimage.distance_transform_edt(thresh)
local_max = peak_local_max(distance_map, indices=False, min_distance=20, labels=thresh)
# Perform connected component analysis then apply Watershed
markers = ndimage.label(local_max, structure=np.ones((3, 3)))[0]
labels = watershed(-distance_map, markers, mask=thresh)
# Iterate through unique labels
for label in np.unique(labels):
if label == 0:
continue
# Create a mask
mask = np.zeros(gray.shape, dtype="uint8")
mask[labels == label] = 255
# Find contours and determine contour area
cnts = cv2.findContours(mask.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
c = max(cnts, key=cv2.contourArea)
color = list(np.random.random(size=3) * 256)
cv2.drawContours(image, [c], -1, color, 4)
cv2.imshow('image', image)
cv2.waitKey()
Here are some other references:
Image segmentation with Watershed Algorithm
Watershed Algorithm: Marker-based Segmentation
How to define the markers for Watershed
Find contours after watershed
It seems like you have a pattern for your objects, and those objects sometimes overlap.
I'd suggest you convolve your image with an object pattern and then process the outcoming scores image.
In more detail:
Suppose for simplicity that your initial image has only one channel. and the object you're looking for looks like this:. this is our pattern. say it's size is [W_p,H_p]
First step: construct new image - scores - where each pixel S in scores = probability that this pixel is the pattern center.
One way to do that is: for each pixel P in the original image, "cut" the [W_p,H_p] patch around P ( e.g. img(Rect(P-W_p/2,P-H_p/2,W_p,H_p))), and subtract patch from pattern to find the "distance" between them (e.g. cv::sum(cv::absdiff(patch, pattern)) function in opencv), and save this sum to S.
Another way to do this is: S = P.clone(); pattern = pattern / cv::sum(pattern);
and then use cv::filter2D for S with pattern...
Now that you have a scores image, you should filter false positives:
1. take the top 2% of the scores( one way is with cv::calcHist)
2. for each pixel that has a neighbor within [W_p,H_p] with a heigher score - turn this pixel to zero !
Now you should remain with image of zeroes where only pattern centers have some value. Hurray!
If you don't know in advance how an object will look like, you can find one object using contours, then 'cut it out' using convex hull of its contour (+ bounding box), and use it as the convolution kernel for finding the rest.

Image boundary after rotation

I am trying to find keypoints in a rotated and then subsampled image using fastcorners. My code:
tfm = Translation((r/2)-1,(c/2)-1) ∘ LinearMap(RotMatrix(-theta)) ∘ Translation(-((r/2)-1),-((c/2)-1))
uR = warp(img1, inv(tfm), indices(img1))
uT = subSample(uR, axes(uF)[1][1], axes(uF)[1][end], t)
kpts = Keypoints(fastcorners(uT, 12, 0.5))
subsampling in vertical direction. So resultant image is no longer a
rectangle but a parallelogram
Now I want to remove keypoints at the boundary of the rotated and subsampled image(i.e. something like d distance from the boundary of the distorted image, parallelogram).
Can you guys suggest something how I can proceed? kpts is storing the cartesian coordinates of the keypoints in the distorted image.
Thanks!
Find the distance to each of the corners of the distorted image from the coordinates of the feature point using the formula mentioned here. Then find the coordinates of the keypoint in the original image by upsampling and then performing an inverse rotation.
For each of the keypoints, transform them with the inverse transformation (including the inverse subsampling) and then check if they are on the boundary of the original image.

Matlab: Extract Image in polar representation from Cartesian

I m trying to compute an efficient way to transform an image in cartesian coordinates into a polar representation. I know some functions such as ImToPolar are doing it and it works perfectly but takes a considerable much time for big images, especially when they require to be processed back and forth.
Here´s my input image:
and then I generate a polar mesh using a cartesian mesh centered at 0 and the function cart2pol(). Finally, I plot my image using mesh(theta, r, Input).
And here´s what I obtain:
Its exactly the image I need and it´s the same as ImToPolar or maybe better.
Since MATLAB knows how to compute it, does anybody know how to extract a matrix in polar representation from this output? Or maybe a fast (like in fast fourier transform) way to compute a Polar transform (and inverse) on MATLAB?
pol2cart and meshgrid and interp2 are sufficient to create the result:
I=imread('http://i.stack.imgur.com/HYSyb.png');
[r, c,~] = size(I);
%rgb image can be converted to indexed image to prevent excessive copmutation for each color
[idx, mp] = rgb2ind(I,32);
% add offset to image coordinates
x = (1:c)-(c/2);
y = (1:r)-(r/2);
% create distination coordinates in polar form so value of image can be interpolated in those coordinates
% angle ranges from 0 to 2 * pi and radius assumed that ranges from 0 to 400
% linspace(0,2*pi, 200) leads to a stretched image try it!
[xp yp] = meshgrid(linspace(0,2*pi), linspace(0,400));
%translate coordinate from polar to image coordinates
[xx , yy] = pol2cart(xp,yp);
% interpolate pixel values for unknwon coordinates
out = interp2(x, y, idx, xx, yy);
% save the result to a file
imwrite(out, mp, 'result.png')

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.

How to use Haar wavelet to detect LINES on an image?

So I have an image like this:
I want to get something like this (I haven't drawn all lines I want but I hope you can get my idea):
I want to use SURF ( (Speeded Up Robust Features) is a robust image descriptor, first presented by Herbert Bay et al. in 2006 ) or something that is based on sums of 2D Haar wavelet responses and makes an efficient use of integral images for finding all straight lines on image. I want to get relative to picture pixel coords start and end points of lines.
So on this picture to find all lines between tiles and those 2 black lines on top.
Is there any such Code Example (with lines search capability) to start from?
I love C and C++ but any other readable code will probably work for me=)
The following is a complete example of applying Hough Transform to detect lines. I am using MATLAB for the job..
The trick is to divide the image into regions and process each differently; this is because you have different "textures" in your scene (tiles on the upper region of the wall are quite different from the darker ones on the bottom, and processing the image all at once wont be optimal).
As a working example, consider this one:
%# load image, blur it, then find edges
I0 = rgb2gray( imread('http://www.de-viz.ru/catalog/new2/Holm/hvannaya.jpg') );
I = imcrop(I0, [577 156 220 292]); %# select a region of interest
I = imfilter(I, fspecial('gaussian', [7 7], 1), 'symmetric');
BW = edge(I, 'canny');
%# Hough Transform and show accumulated matrix
[H T R] = hough(BW, 'RhoResolution',2, 'Theta',-90:0.5:89.5);
imshow(imadjust(mat2gray(H)), [], 'XData',T, 'YData',R, ...
'InitialMagnification','fit')
xlabel('\theta (degrees)'), ylabel('\rho')
axis on, axis normal, colormap(hot), colorbar, hold on
%# detect peaks
P = houghpeaks(H, 20, 'threshold',ceil(0.5*max(H(:))));
plot(T(P(:,2)), R(P(:,1)), 'gs', 'LineWidth',2);
%# detect lines and overlay on top of image
lines = houghlines(BW, T, R, P, 'FillGap',50, 'MinLength',5);
figure, 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
You could try the same procedure for other regions while tuning the parameters to get good results..
Have you tried a simpler approach such as the Hough transform for finding lines? A function to perform this and example are included in OpenCV called cvHoughLines2.
Two-dimensional wavelet transforms are implemented in R using the package waveslim. Specifically, the function dwt2D() uses a C "backend" for speed. You can then apply thresholding to find the lines.

Resources