Detecting horizontal lines in homework using OpenCV - python

I am trying to detect the underlines where students write their answers in the homework, but I cannot get Hough Line Transform to work. It is detecting way to many lines and if I increase thresholds, it will only detect vertical lines. Is there any other method to do this?
This is the code I have based on another post:
gray = cv2.imread(image_path + '000003.png')
edges = cv2.Canny(gray,50,150,apertureSize = 3)
cv2.imwrite('edges-50-150.jpg',edges)
minLineLength=100
lines = cv2.HoughLinesP(image=edges,rho=10,theta=np.pi/180, threshold=100,lines=np.array([]), minLineLength=minLineLength,maxLineGap=80)
a,b,c = lines.shape
for i in range(a):
cv2.line(gray, (lines[i][0][0], lines[i][0][1]), (lines[i][0][2], lines[i][0][3]), (0, 0, 255), 3, cv2.LINE_AA)
cv2.imwrite('houghlines5.jpg',gray)
When I run the code above I get these lines: Hough Transform Result
Edit: original image - Original Image

Related

Detecting handwritten lines using OpenCV

I'm trying to detect underlines and boxes in the following image:
For example, this is the output I'm aiming for:
Here's what I've atempted:
import cv2
import numpy as np
# Load image
img = cv2.imread('document.jpg')
# Convert image to grayscale
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# Apply Gaussian blur to reduce noise
blur = cv2.GaussianBlur(gray, (3, 3), 0)
# Threshold the image
ret, thresh = cv2.threshold(blur, 127, 255, cv2.THRESH_TRUNC)
# Apply Canny Edge Detection
edges = cv2.Canny(thresh, 155, 200)
# Use HoughLinesP to detect lines
lines = cv2.HoughLinesP(edges, rho=1, theta=1*np.pi/180, threshold=100, minLineLength=100, maxLineGap=50)
# Draw lines on image
for line in lines:
x1, y1, x2, y2 = line[0]
cv2.line(img, (x1, y1), (x2, y2), (0, 0, 255), 4)
However, this is the result I get:
Here are my thoughts regarding this problem:
I might need to use adaptive thresholding with Otsu's algorithm to provide a proper binary image to cv2.Canny(). However, I doubt this is the core issue. Here is how the image looks with the current thresholding applied:
cv2.threshold() already does a decent job separating the notes from the page.
Once I get HoughLinesP() to properly draw all the lines (and not the weird scribbles it's currently outputting), I can write some sort of box detector function to find the boxes based on the intersections (or near-intersections) of four lines. As for underlines, I simply need to detect horizontal lines from the output of HoughLinesP(), which shouldn't be difficult (e.g., for any given line, check if the two y coordinates are within some range of each other).
So the fundamental problem I have is this: how do I get HoughLinesP() to output smoother lines and not the current mess it's giving so I can then move forward with detecting boxes and lines?
Additionally, do my proposed methods for finding boxes and underlines make sense from an efficiency standpoint? Does OpenCV provide a better way for achieving what I want to accomplish?

Identifying dark grey hollow cells on light grey background with opencv

I have read through dozens of questions on this topic here. (see eg: 1, 2, 3). There are a lot of helpful explanations of how to play around with parameters etc, watershedding, etc. Yet no matter what I have tried to put together I am still not managing a halfway-passable count of the cells in my image
Here are two examples of the kind of images I need to process.
Initially I was trying to count all the cells, but because of the difference in focus at the edges (where it gets blurrier) I thought it might be easier to count cells within a rectangle the user selects.
I was hopeful this would improve the results, but as you can see, HoughCircles is both selecting as circles empty spaces with nothing in them, and missing many cells:
Other algorithms I have tried have fared worse.
My code:
cap = cv2.VideoCapture(video_file)
frames = []
while True:
frame_exists, curr_frame = cap.read()
if frame_exists:
frames.append(curr_frame)
else:
break
frames = [cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) for frame in frames]
for img in frames:
circles = cv2.HoughCircles(img,
cv2.HOUGH_GRADIENT,
minDist=10,
dp=1.1,
param1=4, #the lower the number the more circles found
param2=13,
minRadius=4,
maxRadius=10)
if circles is not None:
circles = np.round(circles[0, :]).astype("int")
for (x, y, r) in circles:
cv2.circle(img, (x, y), r, (0, 255, 0), 1)
cv2.imshow("result", img)
Editing to add in my not helpful preprocessing code:
denoise = cv2.fastNlMeansDenoising(img, h=4.0, templateWindowSize=15, searchWindowSize=21)
thresh=cv2.adaptiveThreshold(denoise,255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY,41,2)
(and then I passed thresh to HoughCircles instead of img)
It just didn't seem to make any difference...
I believe that these are not circular enough for Hough to work well, you would have to lower param2 too much to account for the lack of uniformity. I would recommend looking into the cv2.findContours method instead and use your 'thresh' image.
https://docs.opencv.org/4.x/dd/d49/tutorial_py_contour_features.html

Drawing a horizontal and vertical line in an image

I have an image that contains a table. There is a horizontal dotted line in the table which I want to replace with a solid horizontal line. Also, I have to draw the vertical lines between the columns. Can anyone help me, what should be my approach? I am using python.
Hint:
Performing an horizontal erosion is a good start to find the positions of the horizontal lines, and delimit sections of the document. Then a large vertical erosion will help you find the columns, though this is more challenging.
I don't know whether this output is good for you or not but as #Yves Daoust said, erosion processes may benefit your problem.
output
import cv2
import numpy as np
image = cv2.imread('hough.jpg')
gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
kernel = np.ones((3,12), np.uint8) #for horizontal erosion
e_im = cv2.erode(gray, kernel, iterations=1) #performing erosion
edges = cv2.Canny(e_im,190,245,apertureSize = 3) #edges
minLineLength=333
#houghlines for detecting those erosion lines
lines = cv2.HoughLinesP(image=edges,rho=0.5,theta=np.pi/180, threshold=222,lines=np.array([]), minLineLength=minLineLength,maxLineGap=7)
a,b,c = lines.shape
# Draw the lines
if lines is not None:
for i in range(0, len(lines)):
l = lines[i][0]
cv2.line(gray, (l[0], l[1]), (l[2], l[3]), (0, 0, 255), 3, cv2.LINE_AA)
cv2.imwrite("e_im.jpg",gray)

Detecting palm lines with OpenCV in Python

I'm studying OpenCV with python by working on a project which aims to detect the palm lines.
What I have done is basically use Canny edge detection and then apply Hough line detection on the edges but the outcome is not so good.
Here is the source code I am using:
original = cv2.imread(file)
img = cv2.cvtColor(original, cv2.COLOR_BGR2GRAY)
save_image_file(img, "gray")
img = cv2.equalizeHist(img)
save_image_file(img, "equalize")
img = cv2.GaussianBlur(img, (9, 9), 0)
save_image_file(img, "blur")
img = cv2.Canny(img, 40, 80)
save_image_file(img, "canny")
lined = np.copy(original) * 0
lines = cv2.HoughLinesP(img, 1, np.pi / 180, 15, np.array([]), 50, 20)
for line in lines:
for x1, y1, x2, y2 in line:
cv2.line(lined, (x1, y1), (x2, y2), (0, 0, 255))
save_image_file(lined, "lined")
output = cv2.addWeighted(original, 0.8, lined, 1, 0)
save_image_file(output, "output")
I tried different parameter sets of Gaussian kernel size and Canny low/high thresholds, but the outcome is either having too much noises, or missing (part of) major lines. Above picture is already the best I get, so far..
Is there anything I should do to get result improved, or any other approach would get better result?
Any help would be appreciated!
What you are looking for is really experimental. You have already done the most important function. I suggest that you tune your parameters to get a reasonable and a noisy number of lines, then you can make some filtering:
using morphological filters,
classification of lines
(according to their lengths, fits on contrasted area...etc)
improving your categories by dividing the area of palm (without
fingers) into a grid (4x4 .. where 4 vertical fingers corners can
define the configs of the grid).
calculate the gradient image,
orientation of lines may help as well
Make a search about the algorithm "cumulative level lines detection", it can help for the certainty of detected lines

How to detect street lines in satellite aerial image using openCV?

I am really new to openCV,I have to detect lines of streets in sattelite imagery
this is the original image
I applied different thresholds and I am able to differentiate background and fg
retval, threshold = cv2.threshold(img1,150, 255, cv2.THRESH_BINARY)
plt.imshow(threshold)
after this, I smoothened to remove noise for HoughLines
# Initialize output
out = cv2.cvtColor(threshold, cv2.COLOR_GRAY2BGR)
# Median blurring to get rid of the noise; invert image
threshold_blur = 255 - cv2.medianBlur(threshold, 5)
plt.imshow(threshold_blur,cmap='gray', vmin = 0, vmax = 255)
Now when I applied hough lines I am getting this
# Detect and draw lines
lines = cv2.HoughLinesP(threshold_blur, 1, np.pi/180, 10, minLineLength=10, maxLineGap=100)
for line in lines:
for x1, y1, x2, y2 in line:
cv2.line(out, (x1, y1), (x2, y2), (0, 0, 255), 2)
plt.imshow(out)
I need lines like this
Why it's not working and what should I do?
Not sure if you would want to do this with only with openCV you may also want to use something like tensorflow.
But if you want to use only openCV here are a few options:
You could try to do dilate and erode. And use findContours, and loop through those contours to find objects with a certain minimum length, and use that to create a line from A to B.
Another solution would be to train a cascade to detect parts of the images that are street sections and connect those points. This is a lot more time consuming though.

Categories