I am trying to develop a program that can detect lanes on the road. I have experimented with both Hough Line Transform and Probabilistic Hough Line Transform. However none of these are getting the results that I want.
Original Image:
Hough Line Transform
Probabilistic Hough Line Transform
It seems that for Hough Line Transform, I can at least detect the entire lane, but unfortunately, the line just goes on infinitely (until they move off the picture), to the point where the lines intersect with each other, which is not a good graphical lane detection marker.
I also tried Probalistic Hough Line Transform, and the green line used for lane detection does not go off to infinitely like the other one, but it fails to mark and detect the entire lane.
I am trying to replicate results here (by writing it in Python)
http://www.transistor.io/revisiting-lane-detection-using-opencv.html
What can I do to fix this problem?
Code:
import numpy as np
import cv2
from matplotlib import pyplot as plt
from PIL import Image
import imutils
def invert_img(img):
img = (255-img)
return img
def canny(imgray):
imgray = cv2.GaussianBlur(imgray, (5,5), 200)
canny_low = 5
canny_high = 150
thresh = cv2.Canny(imgray,canny_low,canny_high)
return thresh
def filtering(imgray):
thresh = canny(imgray)
minLineLength = 1
maxLineGap = 1
lines = cv2.HoughLines(thresh,1,np.pi/180,0)
#lines = cv2.HoughLinesP(thresh,2,np.pi/180,100,minLineLength,maxLineGap)
print lines.shape
# Code for HoughLinesP
'''
for i in range(0,lines.shape[0]):
for x1,y1,x2,y2 in lines[i]:
cv2.line(img,(x1,y1),(x2,y2),(0,255,0),2)
'''
# Code for HoughLines
for i in range(0,5):
for rho,theta in lines[i]:
a = np.cos(theta)
b = np.sin(theta)
x0 = a*rho
y0 = b*rho
x1 = int(x0 + 1000*(-b))
y1 = int(y0 + 1000*(a))
x2 = int(x0 - 1000*(-b))
y2 = int(y0 - 1000*(a))
cv2.line(img,(x1,y1),(x2,y2),(0,0,255),2)
return thresh
img = cv2.imread('images/road_0.bmp')
imgray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
img = imutils.resize(img, height = 500)
imgray = imutils.resize(imgray, height = 500)
thresh = filtering(imgray)
cv2.imshow('original', img)
cv2.imshow('result', thresh)
cv2.waitKey(0)
Cool topic! First of all, why did you add the Gaussian blur? Your source article doesn't mention that at all. If I remove that, I instantly get extra crazy lines, which I can tone down with the canny_low and canny_high. About the best I could find was low=100 and high=180.
Second, you did quite a good job translating the article to Python. However, I think you left out a crucial detail. The author writes:
// Canny algorithm
Mat contours;
Canny(image,contours,50,350);
Mat contoursInv;
threshold(contours,contoursInv,128,255,THRESH_BINARY_INV);
You implement the Canny function (cv2.canny()), but you don't call the threshold function. According to documentation I found, this function "applies a fixed-level threshold to each array element." I experimented with your code and came up with the following.
#thresh = canny(imgray) # original
edges = canny(imgray) # docs refer to return value as "edges"
retval, dst = cv2.threshold(edges, 128, 255,cv2.THRESH_BINARY_INV)
Two values are returned - retval isn't particularly important for us right now. dst is the destination 2D array of image data after thresholding. You would then update your call to cv2.HoughLines and cv2.HoughLinesP replacing "thresh" with "dst." When I did this I got a lot more interesting behavior, though I was not able to find the correct tuning values to make the lines work well.
So, hopefully that gives you some pointers. Try my tips, and also read the article once or twice more to double check that you have the same program flow as the author. This seems like a fun project, have fun!
Related
I have a picture that looks like this.
I do know that in simplecv, you can use:
img = Image('hallway.jpg')
img.show()
img.edges.show()
lines = img.findLines()
lines = lines.filter(lines.length() > 50)
lines.show()
I am wondering if anyone knows any library/document or can point me in any direction, that is able to detect the edges of corners, doors etc in real time or in still images with OpenCV?
Opencv python has implementations of Hough lines which could help. While the algo is heavy, there's a probabilistic version of it that works in realtime. You can even adjust parameters to make it faster at the cost of accuracy.
import cv2
import numpy as np
img = cv2.imread('hallway.jpg')
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray,50,150,apertureSize = 3)
minLineLength = 100
maxLineGap = 10
lines = cv2.HoughLinesP(edges,1,np.pi/180,100,minLineLength,maxLineGap)
for x1,y1,x2,y2 in lines[0]:
cv2.line(img,(x1,y1),(x2,y2),(0,255,0),2)
cv2.imshow("preview", img)
cv2.waitkey(0)
Note that you might have to adjust thresholds in canny and other parameters according to your requirements.
An alternative is to use contours. This might help https://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_imgproc/py_contours/py_contour_features/py_contour_features.html
I'm trying to measure water level in a glass channel using OpenCV and Python. I've decided to use HaughLines in a selected ROI and find the midpoints of the said lines so I can calculate the difference between the ones that I want and multiply it with a set reference size that I'll get later on. So far the part where I find the lines look like this:
import cv2
import numpy as np
def midpoint(ptA, ptB, ptC, ptD):
return ((ptA + ptC) * 0.5, (ptB + ptD) * 0.5)
img = cv2.imread("b2924.JPG")
img = cv2.resize(img, None, fx=3/10, fy=3/10)
r = cv2.selectROI("main", img, False, False)
cropped = img[r[1]:(r[1]+r[3]), r[0]:(r[0]+r[2])]
cv2.destroyWindow("main")
imgray = cv2.cvtColor(cropped, cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(imgray, 35, 75)
lines = cv2.HoughLinesP(edges, 1, np.pi/180, 75, maxLineGap=1000)
midPoint = []
for line in lines:
x1, y1, x2, y2 = line[0]
cv2.line(cropped, (x1, y1), (x2, y2), (0, 0, 255), 1)
mP = midpoint(x1, y1, x2, y2)
midPoint.append(mP)
midPoint.sort(key = lambda x: x[1])
img[r[1]:(r[1]+r[3]), r[0]:(r[0]+r[2])] = cropped
print(lines)
print(midPoint)
cv2.imshow("img", img)
cv2.waitKey()
cv2.destroyAllWindows()
Depending on the image and the ROI I select I find inconsistent results. Image examples and where I select the ROIs:
Note that base of the channel starts where the duct tape reaches. It looks like I can almost never find that exact line because how noisy it is at the base. Right now these threshold values with no morphology seem to give the better results. I tried to use sobel derivative aswell instead of canny but got worse results.
Is it even possible to get exact measurements in this enviroment? Is it a matter of coding or changing the way I take the pictures or both? In the future I will possibly need to map the water profile during heavy turbulance, should I simply move away from OpenCV for that, since the noise is too much? Any help is appreciated.
I would not invest in any image processing with that setup.
If you insist on image processing (if you are only interested in the level at a few positions you might be better off using conventional level sensors)
Add LED panels or any other kind of homogeneous background illumination to the back of the basin. Add dye to the water to get some contrast.
Get rid of the window reflections. Clean the glass.
Alternatively make the background dark and add something to the water that makes it stray light or fluorescent.
You could also add stuff that floats on the surface and is either retroreflective or self-illuminated. That way you would get a bright surface level indicator that is easily detected in an image.
I'm trying to do lane detection, the code is as below, I applied HoughLinesP on canny edge detection's o/p. So the idea is to display only the lines that which are (usually present on the video + more probable to be a lane i.e by picking up the angle). I don't want to use any machine learning algorithms. So please help..
Here are the details :
Code :
import time
import numpy as np
import matplotlib.pyplot as plt
vid = cv2.VideoCapture('4.mp4')
while True:
#cv2.namedWindow('frame',cv2.WINDOW_NORMAL)
ret, img_color = vid.read()
if not ret:
vid = cv2.VideoCapture('5.mp4')
continue
num_rows, num_cols = img_color.shape[:2]
rotation_matrix = cv2.getRotationMatrix2D((num_cols/2, num_rows/2), 270, 0.56) #3
img_rotated = cv2.warpAffine(img_color, rotation_matrix, (num_cols, num_rows))
height, width = img_rotated.shape[:2]
img_resize = cv2.resize(img_rotated,(int(0.8*width), int(0.8*height)), interpolation = cv2.INTER_CUBIC) #2
img_clone = img_resize[10:842,530:1000].copy()
img_roi = img_resize[10+250:842-200,530:1000]
img_gray = cv2.cvtColor(img_roi,cv2.COLOR_BGR2GRAY) #1
kernel = [ [0,-1,0], [-1,5,-1], [0,-1,0] ]
kernel = np.array(kernel)
img_sharp = cv2.filter2D(img_gray,-1,kernel)
blur = cv2.GaussianBlur(img_sharp,(5,5),0)
img_canny = cv2.Canny(blur,130,170, apertureSize = 3) #4
lines = cv2.HoughLinesP(img_canny, 1, np.pi/180, 60, maxLineGap = 240)
if lines is not None:
print(len(lines))
for line in lines:
x1,y1,x2,y2 = line[0]
cv2.line(img_clone, (x1,y1+250), (x2,y2+250), (0,255,0), 2)
#cv2.line(img_clone, (x1,y1), (x2,y2), (255,255,0), 3)
cv2.imshow('frame',img_clone)
cv2.imshow('frame2', img_canny)
k = cv2.waitKey(35) & 0xFF
if k==27 :
break
vid.release()
cv2.destroyAllWindows()
Here's link to videos I'm using
In 4.mp4 you can see that after running this code, a few seconds later a person comes in and there are so many lines as canny detects so many edges in that region, secondly i've fixated region of image for which i want to be dynamic, the idea is to set the region of image on the basis on more probable lanes.
Also there's a cluster of lines appearing, i want to shorten it down to more probable line. Thank you for reading.
You won't get much better results. This is just the nature of your problem. You will now have to go into creating a mathematical model of your lane, and use your hough-lines to correct that model.
E.g. you could track the lane in certain bands of the image using a kalman filter. You then can use the predict step of this filter when you observe line segments that are within the expected angle around your observation band.
I am writing a program in Python to loop through images extracted from the frames of a video and detect lines within them. The images are of fairly poor quality and vary significantly in their content. Here are two examples:
Sample Image 1 | Sample Image 2
I am trying to detect the lasers in each image and look at their angles. Eventually I would like to look at the distribution of these angles and output a sample of three of them.
In order to detect the lines in the images, I have looked at various combinations of the following:
Hough Lines
Canny Edge Detection
Bilateral / Gaussian Filtering
Denoising
Histogram Equalising
Morphological Transformations
Thresholding
I have tried lots of combinations of lots of different methods and I can't seem to come up with anything that really works. What I have been trying is along these lines:
import cv2
import numpy as np
img = cv2.imread('testimg.jpg')
grey = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
equal = clahe.apply(grey)
denoise = cv2.fastNlMeansDenoising(equal, 10, 10, 7, 21)
blurred = cv2.GaussianBlur(denoise, (3, 3), 0)
blurred = cv2.medianBlur(blurred, 9)
(mu, sigma) = cv2.meanStdDev(blurred)
edge = cv2.Canny(blurred, mu - sigma, mu + sigma)
lines = cv2.HoughLines(edge, 1, np.pi/180, 50)
if lines is not None:
print len(lines[0])
for rho,theta in lines[0]:
a = np.cos(theta)
b = np.sin(theta)
x0 = a*rho
y0 = b*rho
x1 = int(x0 + 1000*(-b))
y1 = int(y0 + 1000*(a))
x2 = int(x0 - 1000*(-b))
y2 = int(y0 - 1000*(a))
cv2.line(img, (x1, y1), (x2, y2), (0, 0, 255), 2)
cv2.imshow("preview", img)
cv2.waitKey(0)
This is just one of many different attempts. Even if I can find a method that works slightly better for one of the images, it proves to be much worse for another one. I am not expecting completely perfect results, but I'm sure that they could be better than I've managed so far!
Could anyone suggest a tactic to help me move forward?
Here is one answer. It is an answer that would help you if your camera is in a fixed position and so are your lasers...and your lasers emit from coordinates that you can determine. So, if you have many experiments that happen concurrently with the same setup, this can be a starting point.
The question image information along a polar coordinate system was helpful to get a polar transform. I chose not to use openCV because not everybody can get it going (windows). I took the code from the linked question and played around a bit. If you add his code to mine (without the imports or main method) then you'll have the required functions.
import numpy as np
import scipy as sp
import scipy.ndimage
import matplotlib.pyplot as plt
import sys
import Image
def main():
data = np.array(Image.open('crop1.jpg').convert('LA').convert('RGB'))
origin = (188, -30)
polar_grid, r, theta = reproject_image_into_polar(data, origin=origin)
means, angs = mean_move(polar_grid, 10, 5)
means = np.array(means)
means -= np.mean(means)
means[means<0] = 0
means *= means
plt.figure()
plt.bar(angs, means)
plt.show()
def mean_move(data, width, stride):
means = []
angs = []
x = 0
while True:
if x + width > data.shape[1]:
break
d = data[:,x:x+width]
m = np.mean(d[d!=0])
means.append(m)
ang = 180./data.shape[1] * float(x + x+width)/2.
angs.append(ang)
x += stride
return means, angs
# copy-paste Joe Kington code here
Image around the upper source.
Notice that I chose one laser and cropped a region around its source. This can be done automatically and repeated for each image. I also estimated the source coordinates (188, -30) (in x,y form) based on where I thought it emitted from. Following image(a gimp screenshot!) shows my reasoning(it appeared that there was a very faint ray that I traced back too and took the intersection)...it also shows the measurement of the angle ~140 degrees.
polar transform of image(notice the vertical band if intensity...it is vertical because we chose the correct origin for the laser)
And using a very hastily created moving window mean function and rough mapping to degree angles, along with a diff from mean + zeroing + squaring.
So your task becomes grabbing these peaks. Oh look ~140! Who's your daddy!
In recap, if the setup is fixed, then this may help you! I really need to get back to work and stop procrastinating.
See, I have been trying to detect books in a bookshelf:
I used Contours for bounding boxes. However, I just want to capture the actual book objects. If I lessen the threshold from Canny, it won't detect the book edges themselves but it detects the book titles or some images from the spine.
I used houghlines and it worked well for detecting the book edge. How can I apply bounding boxes but with houghlines instead of contours?
code I used for Contour finding:
edges = cv2.Canny(blur,thresh,thresh*2)
drawing = np.zeros(img.shape,np.uint8)
contours,hierarchy = cv2.findContours(edges,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
for cnt in contours:
x,y,w,h = cv2.boundingRect(cnt)
cv2.rectangle(img,(x,y),(x+w,y+h),(0,255,0),2)
rect = cv2.minAreaRect(cnt)
box = cv2.cv.BoxPoints(rect)
box = np.int0(box)
where:
img = cv2.imread('books3.jpg')
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray,(5,5),0)
For the houghlines:
lines = cv2.HoughLines(edges,1,np.pi/180,120)
for rho,theta in lines[0]:
a = np.cos(theta)
b = np.sin(theta)
x0 = a*rho
y0 = b*rho
x1 = int(x0 + 1000*(-b))
y1 = int(y0 + 1000*(a))
x2 = int(x0 - 1000*(-b))
y2 = int(y0 - 1000*(a))
where:
im = cv2.imread('books2.jpg')
gray = cv2.cvtColor(im,cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray,100,300,apertureSize = 3)
Thank you so much in advance.
I am actually working on something similar myself. trying to segment the books from one another in a bookshelf. I wish to ask what is the progress on your side so far?
I have yet to tried contours method. However, what I did try was to pre-process the image, canny the image before using HoughLines. The image belows shows a rough result.
I admit I have to perfectly segment out the books either. As you can see in the image, there are more lines then I actually wanted due to the nature of the book spine. I am looking into preprocessing methods that can help me to rid such problem.
I noticed you mentioned that "If I lessen the threshold from Canny, it won't detect the book edges themselves but it detects the book titles or some images from the spine." Maybe for HoughLine Parameters, you can adjust the theta? for instance to 90 degrees so that the book titles, etc will not be detected.
You can also try HoughLineP which is basically Probabilistic Hough Line Transform. More details about that can be found in:
http://docs.opencv.org/doc/tutorials/imgproc/imgtrans/hough_lines/hough_lines.html
Hope my methods give some ideas.I also hope to hear updates from you in regards to your contour method. Hope we can share tips and work together as we have a common goal (: Hope to hear from you soon.