Detecting the lines (structure edges) in a charcoal drawing image - python

I want to detect the all lines of a structure's edges but I can't detect every line. Does anyone know how to do that?
I want to detect lines in this picture but it's really noisy and I can't detect every line. I tried denoising, blurring and other things then I used canny line detection but it didn't find every line.
Here is the original image:
I want to detect every edge of those structures.
Can anyone do that?
I got this with denoising:
My code:
gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
denoised = cv2.fastNlMeansDenoising(gray_image,None,20)
blur_image = cv2.medianBlur(denoised,5)
cv2.imshow('blur_image 2',blur_image)
edges = cv2.Canny(blur, 40, 255)
cv2.imshow('canny_image',edges)
# Hough Transform
lines = cv2.HoughLinesP(edges, 1, np.pi/180, 50, minLineLength=50, maxLineGap=10)
Can anyone help me?

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?

Removing glare with opencv and keeping edges removed from the glare

I have this image : https://imgur.com/9A7542w
And i am trying to get the contours of the image but as we can see in this : https://imgur.com/VU7KqiS
where there is glare, the contours of some circles are not drawn.
I assume that if i get the glare off on this photo, when i use canny, the edges will be drawn correctly?
I am new to openCV, i've read some post on here and tried out some techniques, but it didn't work out at all.
Note: i am doing this in python
Anyone could help ? Thanks a lot.
What i tried first :
import cv2 as cv
img = cv.imread('Photos/board.jpg')
canny = cv.Canny(img, 125, 175)
contours, hierarchies = cv.findContours(canny, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_NONE)
blank = np.zeros(img.shape, dtype='uint8')
cv.drawContours(blank, contours, -1, (0,0,255),1)
cv.imshow('Contours drawn', blank)
results : https://imgur.com/yLVFCh2
Second attempt a bit better but useless things appears in the result
adaptive_thresh = cv.adaptiveThreshold(gray, 255, cv.ADAPTIVE_THRESH_MEAN_C, cv.THRESH_BINARY, 13, 2)
cv.imshow('Adaptive thresholding', adaptive_thresh)
canny = cv.Canny(adaptive_thresh, 125, 175)
cv.imshow('Canny edges', canny)
Results (Theres so much white pixels that appear on the photo : https://imgur.com/mqljl1m
I think the easiest way to do this is to change the 2nd value of your Canny detection like this :
canny = cv.Canny(img, 25, 175)
the lower threshold (second argument) is set lower then you can avoid this glare effect. More info here
From my point of view, you can also work in hsv space which is more confomfortable if you want to extract informations from images with effects like this. More info about hsv. The Fig. 3 a) speaks for itself.
Here is the full code, you had some errors in yours (and maybe you use an old opencv release)
import numpy as np
img = cv.imread(r'C:\Users\MyUser\Desktop\board.jpeg')
canny = cv.Canny(img, 25, 175)
img2, contours, hierarchy = cv.findContours(canny, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_NONE)
blank = np.zeros(img.shape, dtype='uint8')
cv.drawContours(blank, contours, -1, (0,0,255),1)
cv.imshow('Contours drawn', blank)
cv.waitKey(0)
EDIT: I also want to tell you that it'll be difficult to use the extracted coordinates here. You'd better use circle detection and line detection to extract and use the coordinates of the board and pucks.

how to draw outlines of objects on an image to a separate image

i am working on a puzzle, my final task here is to identify edge type of the puzzle piece.
as shown in the above image i have mange to rotate and crop out every edge of the piece in same angle. my next step is to separate the edge line into a separate image like as shown in the image bellow
then to fill up one side of the line with with a color and try to process it to decide what type of edge it is.
i dont see a proper way to separate the edge line from the image for now.
my approach::
one way to do is scan pixel by pixel and find the black pixels where there is a nun black pixel next to it. this is a code that i can implement. but it feels like a primitive and a time consuming approach.
so if there you can offer any help or ideas, or any completely different way to detect the hollows and humps.
thanks in advance..
First convert your color image to grayscale. Then apply a threshold, say zero to obtain a binary image. You may have to use morphological operations to further process the binary image if there are holes. Then find the contours of this image and draw them to a new image.
A simple code is given below, using opencv 4.0.1 in python 2.7.
bgr = cv2.imread('puzzle.png')
gray = cv2.cvtColor(bgr, cv2.COLOR_BGR2GRAY)
_, roi = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY)
cv2.imwrite('/home/dhanushka/stack/roi.png', roi)
cont = cv2.findContours(roi, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
output = np.zeros(gray.shape, dtype=np.uint8)
cv2.drawContours(output, cont[0], -1, (255, 255, 255))
# removing boundary
boundary = 255*np.ones(gray.shape, dtype=np.uint8)
boundary[1:boundary.shape[0]-1, 1:boundary.shape[1]-1] = 0
toremove = output & boundary
output = output ^ toremove

OpenCV HoughLines

Currently I'm working on a free-time project, which consists of parsing a video feed into a HTML template. In order to differentiate types of DOMs, I use 4 different angled lines in a rectangle (please ignore the triangle and the circle), but to calculate their angle, I must first find the lines. OpenCV's HoughLinesP comes in handy, but for whatever reason, it finds only a few lines.
Here are some sample images, on the left, that's the source image (with the found lines drawn on it, colored green), and on the left, that's the processed image. First, the source is converted to grayscale, then I run Canny on it. (I tried blurring it too)
In my opinion only a small amount of lines are detected. This makes me question my threshold parameters. Currently, they are the following:
gray = cv2.cvtColor(src, cv2.COLOR_BGR2GRAY)
canny = cv2.Canny(gray, 50, 150, apertureSize=3)
And then for the line detection:
rho = 1.5
theta = pi / 180.
threshold = 60
min_line_length = 100
max_line_gap = 10
lines = cv2.HoughLinesP(lineimage, rho, theta, threshold, min_line_length, max_line_gap)
Please note, that I'm only running edge/line detection on components which have a parent, that's why there are no lines detected on the most-outer component.
Am I doing something wrong? Are my parameters off the grid? I would greatly appreciate any suggestion on how to improve it!
Thank you in advance!

Identify a line on an image using OpenCV

This is the frame I want to process. I wanted to identify a line in an image. Although, I did that via Canny Edge detection, I tried using the corners too (expecting the dots to cover most of the lines). Counter-intuitively, more dots appeared on the noise in the image than the actual line. I was wondering if anyone knows of a function in OpenCV (Python) to connect these dots intelligently, only to connect over the line, and not the noise.
Help will be much appreciated.
I wanted to identify this black line
import cv2
import numpy as np
img = cv2.imread('fw1.jpeg')
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.imwrite('houghlines5.jpg',img)
I think you should increase contrast and get rid of noise in the first place. Contrast increase is described here: https://stackoverflow.com/a/46522515/8682088
Code from source above:
cv::Mat img = cv::imread("E:\\Workspace\\KS\\excercise\\oBwBH.jpg", 0);
cv::Mat workingMat;
cv::GaussianBlur(img, workingMat, cv::Size(101, 101), 31, 31); //high blur to extract background light
img = img - 0.7*work; //adjust light level
cv::normalize(img, img, 0, 255, cv::NORM_MINMAX); \\use whole range
cv::medianBlur(img, img, 5); \\remove noise
cv::Canny(img, work, 100, 200); \\extract lines; you could do hough lines instead since it has canny inside.
After that I suggest using HoughLines or HoughLinesP in opencv library.

Categories