微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Python - 将坐标映射到直线和圆弧列表中

如何解决Python - 将坐标映射到直线和圆弧列表中

我正在尝试将坐标数组(表示封闭形状)解析为 Python 中的一组直线和圆弧(我使用 OpenCV 进行边缘检测)。

简而言之,我想要实现的是使用绘制此示例图像的坐标

Example shape

进入这组线和弧

Set of arcs

显然,弧线不像图像中那样定义,而是类似于“像素化”弧线。

是否有任何实用程序可以帮助进行这种处理?

解决方法

让我们将图像加载为灰度,将其阈值设置为黑白并反转颜色,稍微腐蚀一下,使用 Canny 边缘检测,然后使用霍夫线检测(主要是在 this tutorial 之后):

import cv2
import numpy as np
import math
import random

src = cv2.imread("s34I0.png",cv2.IMREAD_GRAYSCALE)
thr,bw = cv2.threshold(src,128,255,cv2.THRESH_BINARY_INV)
eroded = cv2.erode(bw,np.ones((5,5),np.uint8))
canny = cv2.Canny(src,50,200,None,3)

lines = cv2.HoughLines(canny,1,np.pi / 180,150,0)
lines = [list(x[0]) for x in lines]

def draw_line(img,line,color,thickness):
    rho,the = line
    a   = math.cos(the)
    b   = math.sin(the)
    x0  = a * rho
    y0  = b * rho
    pt1 = (int(x0 + 1000 * (-b)),int(y0 + 1000 * (a)))
    pt2 = (int(x0 - 1000 * (-b)),int(y0 - 1000 * (a)))

    cv2.line(img,pt1,pt2,thickness,cv2.LINE_AA)

enter image description here

不幸的是,我们为每个直线段检测到两条平行线。让我们用它们的中线替换每对这样的接近平行线:

lines_ = []

def midline(line1,line2):
    return [(x + y) / 2 for x,y in zip(line1,line2)]

used = []
for l1 in lines:
    if l1 in used: continue
    for l2 in lines:
        if l2 in used: continue
        if l1 is l2: continue
        if (abs(l1[0] - l2[0]) < 20) and (abs(l1[1] - l2[1]) < 1):
            lines_.append(midline(l1,l2))
            used.append(l1)
            used.append(l2)
            continue
lines = lines_

enter image description here

现在,让我们为直线创建二进制掩码。对于每条直线,我们创建一个临时的二进制黑色图像(所有像素值都为零),然后在其上绘制一条粗白线(与原始图像上的线条相同或略粗)。然后我们对原始阈值图像和临时线图像进行逻辑与运算,因此我们得到两者共有的像素 - 即线的二值掩码。

line_masks = []
for i,line in enumerate(lines):
    line_img = np.zeros(bw.shape)
    draw_line(line_img,10) # 10 pixel thick white line
    common = np.logical_and((bw != 0),(line_img != 0))
    line_masks.append(common)

从原始黑白图像中删除蒙版像素,因此应只保留弧线。不幸的是,一些垃圾仍然存在,因为原始图像中的线条并不完美。为了摆脱这种情况,我们可以将霍夫线画得更粗(比如,15 或 20 个像素而不是 10 个像素),但这样它们会占用太多的弧形像素。相反,我们可以对生成的图像进行一点腐蚀-扩张,以摆脱垃圾:

for lm in line_masks:
    bw[lm] = 0

bw = cv2.erode(bw,np.uint8))
bw = cv2.dilate(bw,np.uint8))

enter image description here

让我们为弧创建二进制掩码。 OpenCV 中没有检测弧线的功能,但对于这种情况,我们可以使用连接组件检测:

arc_masks = []
num,labels = cv2.connectedComponents(bw)
for i in range(1,num):
    arc_masks.append(labels == i)

现在我们有了蒙版,让我们通过绘制原始图像来可视化它们。线条将有随机的绿色阴影,弧线 - 蓝色:

line_colors = [(0,random.randint(127,256),0) for _ in line_masks]
arc_colors = [(random.randint(127,0) for _ in arc_masks]
dst = cv2.imread("s34I0.png")
for color,mask in zip(line_colors,line_masks):
    dst[mask] = color

for color,mask in zip(arc_colors,arc_masks):
    dst[mask] = color

enter image description here

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。