在 openCV 和 python 中计算二值图像中的曲线、角度和直线

2024-04-15

我想编写一个工具来查找图像中每个有界对象内的角度、曲线和直线的数量。 所有输入图像均为白底黑字,并且全部代表字符。

如图所示,对于每个有界区域,记录每个形状的出现。最好能够有一个阈值,规定曲线必须弯曲到什么程度才能被视为曲线而不是角度等。对于直线和角度也是如此。

我已经使用霍夫线变换来检测其他图像上的直线,它可能与我认为的一些东西结合使用。

我对 opencv 以外的其他库持开放态度 - 这正是我有一些经验的。

提前致谢

编辑: 因此,根据马库斯的回答,我使用以下命令编写了一个程序findContours() with CHAIN_APPROX_SIMPLE.

输入“k”会产生一个有点奇怪的结果,它正确地识别了角度周围的一些点,但“腿”(下部对角线部分)上有很多很多点。我不确定如何将其分为直线、角度和曲线。

Code:

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()

Img example: K-helvitica


您可以使用查找轮廓 https://docs.opencv.org/3.4/d4/d73/tutorial_py_contours_begin.html有选项CHAIN_APPROX_SIMPLE.

  • 角度小于某个阈值的点是角点。
  • 角度超过某个阈值的点位于直线上,应将其删除。
  • 距离大于某个阈值的两个相邻点是直线的端点。
  • 被识别为角点的两个相邻点是直线的端点。
  • 所有其他点都属于一些曲线细节。

Update:

您可以从以下代码开始。它展示了如何平滑直线,如何将多个角点合并为一个,以及如何计算每个点的距离和角度。要达到所需的结果,您还有一些工作要做,但我希望它能朝着正确的方向发展。

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()
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在 openCV 和 python 中计算二值图像中的曲线、角度和直线 的相关文章

随机推荐