我有一些灰度图像,如下所示:
https://xqueryfiddle.liberty-development.net/pPgCcon/1
它们是具有不同标记样式的灰度线形图(可以是正方形,圆形,星形,点形。列表会继续显示)。
我想获取标记的坐标。我计划将数据线读取为折线,并使用角点检测算法检测顶点,但是从我一直以来的角度来看,角点检测更适合3D空间。
我的问题是:是否可以将折线作为折线读取并提取顶点的坐标?有没有办法使用霍夫变换通过opencv检测折线?
预先感谢
编辑
原始图像如下:
答案 0 :(得分:2)
怎么样?
提取行
import numpy as np
import cv2
img = cv2.imread('origin.png')
## 1. choose HSV
# rough hsv values in this image.
# grid(gray)=(0, 0, 174)
# border(black)=(0, 0, 15)
# back ground(white)=(0, 0, 254)
# hsv value including border and back ground
hsv_min = (0, 0, 0) # Lower end of the HSV range
hsv_max = (10, 10, 255) # Upper end of the HSV range
# Transform image to HSV color space
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
# Threshold based on HSV values
color_thresh = cv2.inRange(hsv, hsv_min, hsv_max)
# Invert the image
invert = cv2.bitwise_not(color_thresh)
## If you need perform skeletonization, use skimage.
#import skimage
#from skimage.morphology import skeletonize
#color_thresh = skeletonize(skimage.img_as_float(color_thresh))
#color_thresh = color_thresh.astype('uint8') * 255
cv2.imwrite("lines.png", invert)
## 2. cv2.HoughLinesP
# Actually, parameter tuning will be necessary
minLineLength = 100
maxLineGap = 100
lines = cv2.HoughLinesP(color_thresh, 2, np.pi/180,70,minLineLength,maxLineGap)
# lines = [[[319 321 431 188]], ... ,[[ 83 283 195 399]]]
lines = [x.flatten() for x in lines]
# lines = [[319, 321, 431, 188], ... ,[ 83, 283, 195, 399]]
# sort by first element
lines = sorted(lines, key=lambda x : x[0])
# drow lines
for line in lines:
x1,y1,x2,y2 = line
cv2.line(img,(x1,y1),(x2,y2),(0,255,0),2)
## 3. Find the intersection of two lines
def cross_point(segment_p1p2, segment_p3p4):
'''
Intersection point of two lines
p1p2:{p1(a,b)、p2(c,d)}
p3p4:{p3(e,f)、p4(g,h)}
'''
a = segment_p1p2[0]
b = segment_p1p2[1]
c = segment_p1p2[2]
d = segment_p1p2[3]
e = segment_p3p4[0]
f = segment_p3p4[1]
g = segment_p3p4[2]
h = segment_p3p4[3]
dev = (d-b)*(g-e)-(c-a)*(h-f)
d1 = f*g-e*h
d2 = b*c-a*d
xp = (d1*(c-a)-d2*(g-e))/dev
yp = (d1*(d-b)-d2*(h-f))/dev
return (xp, yp)
# draw circles
for i in range(len(lines)-1):
x, y = cross_point(lines[i], lines[i+1])
cv2.circle(img,(int(x),int(y)), 5, (255,0,0), 2)
cv2.imwrite("out.png",img)
[excursus]
HoughLinesP可能会返回多条重叠的线。
在这种情况下,最好进行以下处理。
# [81, 281, 201, 406] and [81, 279, 198, 400] are overlapping
# [435, 184, 557, 214] and [451, 187, 558, 213] are overlapping
lines = [[81, 281, 201, 406],
[81, 279, 198, 400],
[193, 405, 313, 327],
[312, 329, 437, 180],
[435, 184, 557, 214],
[451, 187, 558, 213]]
import math
def is_close(data1, data2, threshold=10):
'''
e.g. data1=[x, y] , data1=[x, y, z]
`threshold` is euclidean distance.
calculate the distance between two points, and determine if they are in the neighborhood.
'''
return math.sqrt(sum((d1-d2)**2 for d1, d2 in zip(data1, data2))) < threshold
# sort by first element
lines = sorted(lines, key=lambda x : x[0])
chained_lines=[lines[0]]
index=0
for i in range(len(lines)):
if i < index:
continue
end_of_line = lines[i][-2:]
# generator which return the index of the chained elements
y = (i for i, v in enumerate(lines) if is_close(end_of_line, v[:2]))
# get the index of the first element
chained_index = next(y, None)
if chained_index != None and chained_index > index:
index = chained_index
chained_lines.append(lines[index])
print(chained_lines)
chained_lines
[[81,281,201,406],[193,405,313,327],[312,329,437,180],[435,184,557,214]]
提取边界
import numpy as np
import cv2
img = cv2.imread('origin.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, bin_img = cv2.threshold(gray, 1, 255, cv2.THRESH_BINARY_INV)
minLineLength = 100
maxLineGap = 100
lines = cv2.HoughLinesP(bin_img, 2, np.pi/180,70,minLineLength,maxLineGap)
lines = [x.flatten() for x in lines]
# drow lines
for line in lines:
x1,y1,x2,y2 = line
cv2.line(img,(x1,y1),(x2,y2),(0,255,0),2)
cv2.imwrite("out2.png",img)