The idea of solution I found was the following:
- Upload image
- Pull out the green
- Threshold to binarize
- Find lines with Probabilistic Hough Transform
- Skeletonize or Thin
Upload image
img = cv2.imread('C:\\Users\\Desktop\\teste\\1.jpg')
Pull out the green
Converts to HSV and makes the color Slice green.
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
mask = cv2.inRange(hsv, (36, 0, 0), (70, 255,255))
## slice no verde
imask = mask>0
verde = np.zeros_like(img, np.uint8)
verde[imask] = img[imask]
cv2.imwrite('C:\\Users\\Desktop\\teste\\2.jpg', verde)
Threshold
Uses Threshold to transform HSV image channel V into binary
(canal_h, canal_s, canal_v) = cv2.split(verde)
retval, threshold = cv2.threshold(canal_v, 130, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)
cv2.imwrite('C:\\Users\\Desktop\\teste\\3.jpg', canal_v)
Probabilistic Transformation of Hough
Perform the Rough transform with the parameters th
, minLineLength
and maxLineGap
variables, in which you can change them and test.
And change the width of the line created in: cv2.line(img,(x1,y1),(x2,y2),(0,0,0),15)
where number 15 is the line width.
img = np.ones((3000,4000,3), np.uint8)
generates a white image 4000 px x 3000 px, but the Opencv library uses binarization differently than numpy. Where numpy uses 0.1 and Opencv 0.255, therefore, to solve this problem: img[img==1]=255
th=255
minLineLength = 100
maxLineGap = 10
lines = cv2.HoughLinesP(threshold,1,np.pi/180,th,minLineLength,maxLineGap)
img = np.ones((3000,4000,3), np.uint8)
img[img==1]=255
for x in range(0, len(lines)):
for x1,y1,x2,y2 in lines[x]:
cv2.line(img,(x1,y1),(x2,y2),(0,0,0),15)
cv2.imwrite('C:\\Users\\Desktop\\teste\\4.jpg', img)
The transform was not very well formed by the image characteristics, in which the contrast and dimensions of the photo object are not perfect, probably a segmentation with CNN is better.
Skeletonize
Using the following function:
def find_skeleton3(img):
# https://stackoverflow.com/a/42846932/7690982
skeleton = np.zeros(img.shape,np.uint8)
eroded = np.zeros(img.shape,np.uint8)
temp = np.zeros(img.shape,np.uint8)
retval,thresh = cv2.threshold(img,127,255,cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)
kernel = cv2.getStructuringElement(cv2.MORPH_CROSS,(3,3))
iters = 0
while(True):
cv2.erode(thresh, kernel, eroded)
cv2.dilate(eroded, kernel, temp)
cv2.subtract(thresh, temp, temp)
cv2.bitwise_or(skeleton, temp, skeleton)
thresh, eroded = eroded, thresh # Swap instead of copy
iters += 1
if cv2.countNonZero(thresh) == 0:
return (skeleton,iters)
to obtain the skeleton of the result of the Hough Transform, and then dilating the result of the Skeletonize:
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
esqueleto, iters = find_skeleton3(img)
esqueleto = cv2.dilate(esqueleto,kernel,iterations = 4)
cv2.imwrite('C:\\Users\\Desktop\\teste\\5.jpg', esqueleto)
Complete code
import cv2
import numpy as np
kernel = cv2.getStructuringElement(cv2.MORPH_CROSS, (3, 3))
def find_skeleton3(img):
# https://stackoverflow.com/a/42846932/7690982
skeleton = np.zeros(img.shape,np.uint8)
eroded = np.zeros(img.shape,np.uint8)
temp = np.zeros(img.shape,np.uint8)
retval,thresh = cv2.threshold(img,127,255,cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)
kernel = cv2.getStructuringElement(cv2.MORPH_CROSS,(3,3))
iters = 0
while(True):
cv2.erode(thresh, kernel, eroded)
cv2.dilate(eroded, kernel, temp)
cv2.subtract(thresh, temp, temp)
cv2.bitwise_or(skeleton, temp, skeleton)
thresh, eroded = eroded, thresh # Swap instead of copy
iters += 1
if cv2.countNonZero(thresh) == 0:
return (skeleton,iters)
img = cv2.imread('C:\\Users\\Desktop\\teste\\1.jpg')
#HSV
#https://stackoverflow.com/a/47483966/7690982
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
mask = cv2.inRange(hsv, (36, 0, 0), (70, 255,255))
## slice no verde
imask = mask>0
verde = np.zeros_like(img, np.uint8)
verde[imask] = img[imask]
cv2.imwrite('C:\\Users\\Desktop\\teste\\2.jpg', verde)
#Threshold
(canal_h, canal_s, canal_v) = cv2.split(verde)
retval, threshold = cv2.threshold(canal_v, 130, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)
cv2.imwrite('C:\\Users\\Desktop\\teste\\3.jpg', canal_v)
#Hough
minLineLength = 100
maxLineGap = 10
lines = cv2.HoughLinesP(threshold,1,np.pi/180,255,minLineLength,maxLineGap)
img = np.ones((3000,4000,3), np.uint8)
img[img==1]=255
for x in range(0, len(lines)):
for x1,y1,x2,y2 in lines[x]:
cv2.line(img,(x1,y1),(x2,y2),(0,0,0),15)
cv2.imwrite('C:\\Users\\Desktop\\teste\\4.jpg', img)
#Skeletonize
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
esqueleto, iters = find_skeleton3(img)
esqueleto = cv2.dilate(esqueleto,kernel,iterations = 4)
cv2.imwrite('C:\\Users\\Desktop\\teste\\5.jpg', esqueleto)
Do you have an example image and can draw in the Paint what you want? It would help other users respond.
– danieltakeshi
Thank you so much for the comment. I added 3 images, trying to make the problem very illustrative.
– Camila Eletrica