我想编写一个工具来查找图像中每个有界对象内的角度、曲线和直线的数量。所有输入图像都将是白底黑字,并且都代表字符。
如图所示,对于每个有界区域,每个形状的出现都会被记录下来。最好能够有一个阈值,以决定曲线必须弯曲到什么程度才能被视为曲线而不是角度等。直线和角度也是如此。
我已经使用霍夫线变换来检测其他图像上的直线,我认为它可能与这里的某些东西结合使用。
除了 opencv 之外,对其他库也持开放态度 - 这只是我的一些经验。
提前致谢
编辑:所以基于 Markus 的回答,我使用findContours()with制作了一个程序CHAIN_APPROX_SIMPLE。
findContours()
CHAIN_APPROX_SIMPLE
输入“k”会产生一个有点奇怪的结果,它正确地识别了角度周围的一些点,但“腿”(下对角线部分)上有很多点。我不确定如何将其分割成直线、角度和曲线。
代码:
import numpy as np img = cv2.imread('Helvetica-K.png') gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) blurred = cv2.GaussianBlur(gray, (3, 3), 0) edges = cv2.Canny(blurred, 50, 150, apertureSize=3) ret, thresh = cv2.threshold(gray, 180, 255, cv2.THRESH_BINARY_INV) contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) #cv2.drawContours(img, contours, 0, (0,255,0), 1) #Coordinates of each contour for i in range(len(contours[0])): print(contours[0][i][0][0]) print(contours[0][i][0][1]) cv2.circle(img, (contours[0][i][0][0], contours[0][i][0][1]), 2, (0,0,255), -1) cv2.imshow('img', img) cv2.waitKey(0) cv2.destroyAllWindows()
图片示例:
您可以将findContours与选项一起使用CHAIN_APPROX_SIMPLE。
更新:
以下是一些您可以开始使用的代码。它展示了如何平滑直线、如何将多个角点合并为一个角点以及如何计算每个点的距离和角度。您还需要做一些工作才能获得所需的结果,但我希望它能引导您朝着正确的方向前进。
import numpy as np import numpy.linalg as la import cv2 def get_angle(p1, p2, p3): v1 = np.subtract(p2, p1) v2 = np.subtract(p2, p3) cos = np.inner(v1, v2) / la.norm(v1) / la.norm(v2) rad = np.arccos(np.clip(cos, -1.0, 1.0)) return np.rad2deg(rad) def get_angles(p, d): n = len(p) return [(p[i], get_angle(p[(i-d) % n], p[i], p[(i+d) % n])) for i in range(n)] def remove_straight(p): angles = get_angles(p, 2) # approximate angles at points (two steps in path) return [p for (p, a) in angles if a < 170] # remove points with almost straight angles def max_corner(p): angles = get_angles(p, 1) # get angles at points j = 0 while j < len(angles): # for each point k = (j + 1) % len(angles) # and its successor (pj, aj) = angles[j] (pk, ak) = angles[k] if la.norm(np.subtract(pj, pk)) <= 4: # if points are close if aj > ak: # remove point with greater angle angles.pop(j) else: angles.pop(k) else: j += 1 return [p for (p, a) in angles] def main(): img = cv2.imread('abc.png') gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) ret, thresh = cv2.threshold(gray, 180, 255, cv2.THRESH_BINARY_INV) contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) for c in contours: # for each contour pts = [v[0] for v in c] # get pts from contour pts = remove_straight(pts) # remove almost straight angles pts = max_corner(pts) # remove nearby points with greater angle angles = get_angles(pts, 1) # get angles at points # draw result for (p, a) in angles: if a < 120: cv2.circle(img, p, 3, (0, 0, 255), -1) else: cv2.circle(img, p, 3, (0, 255, 0), -1) cv2.imwrite('out.png', img) cv2.destroyAllWindows() main()