首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何填充opencv的空白线

如何填充opencv的空白线
EN

Stack Overflow用户
提问于 2021-05-07 12:08:09
回答 4查看 813关注 0票数 2

我有这样的形象:

在我应用了一些处理(例如cv2.Canny() )之后,现在看起来是这样的:

你可以看到黑线变成了空心的。我试过侵蚀和膨胀,但如果我做了很多次,两个入口将关闭(意思是成为连接线或封闭轮廓)。

如何使这些线条像下面的图像一样坚固,同时保持两个入口不受影响?

更新1

我用几张照片测试了下面的答案,但是代码似乎是自定义的,只能处理这一张特定的图片。由于SOF的限制,我不能上传大于2MB的照片,所以为了便于测试,我将它们上传到我的Microsoft OneDrive文件夹中。

https://1drv.ms/u/s!Asflam6BEzhjgbIhgkL4rt1NLSjsZg?e=OXXKBK

更新2

我找到@fmw42 42的帖子作为回答,因为他的回答是最详细的。它没有回答我的问题,但指出了正确的方式处理迷宫,这是我的最终目标。我喜欢他回答问题的方法,首先告诉你每一步应该做什么,这样你才能清楚地知道如何完成任务,然后自始至终提供完整的代码示例。非常有帮助。

由于SOF的限制,我只能得到一个答案。如果允许多个答案,我也会选择Shamshisaz.Navid的答案。他的回答不仅指向了解决问题的正确方向,而且可视化的解释对我来说也很有效~!我想,对于所有试图理解为什么需要每一行代码的人来说,这同样有效。此外,他在评论中跟进了我的问题,这使得SOF有一点交互性:)

Ann Zen的答案中的阈值跟踪栏也是人们快速找到最优值的一个非常有用的提示。

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2021-05-07 23:18:51

这里有一种方法可以处理这个迷宫,并在Python/OpenCV中纠正它。

gray

  • Threshold

  • Use

  • 将输入的

  • 转换成接近于background

  • Get的形态学,以去除最薄的(外部)黑线,

  • 在输入

  • 的宽度和高度的1/4以上的轮廓上反转外部的

  • ,将这些轮廓画成黑色background

  • Get上的白线,从白色轮廓线图像

H 119将凸起的船体绘制为黑色background

  • Use GoodFeaturesToTrack上的白线,从而从白色船体上画出4个角。直线图像

  • 按相对于质心的角度对四个角进行排序,以便按顺时针方向排列:左上角,右上、右下角、bottom-left

  • Set这些点作为输入

  • 的共轭控制点数组,使用输入的1/2维数为output

  • Compute定义共轭控制点数组,透视变换矩阵

  • 利用透视矩阵

  • 保存结果

来校正输入图像。

输入:

代码语言:javascript
运行
复制
import cv2
import numpy as np
import math

# load image
img = cv2.imread('maze.jpg')
hh, ww = img.shape[:2]

# convert to gray
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# threshold
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)[1]

# use morphology to remove the thin lines
kernel = cv2.getStructuringElement(cv2.MORPH_RECT , (5,1))
thresh = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)

# invert so that lines are white so that we can get contours for them
thresh_inv = 255 - thresh

# get external contours
contours = cv2.findContours(thresh_inv, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
contours = contours[0] if len(contours) == 2 else contours[1]

# keep contours whose bounding boxes are greater than 1/4 in each dimension
# draw them as white on black background
contour = np.zeros((hh,ww), dtype=np.uint8)
for cntr in contours:
    x,y,w,h = cv2.boundingRect(cntr)
    if w > ww/4 and h > hh/4:
        cv2.drawContours(contour, [cntr], 0, 255, 1)
        
# get convex hull from  contour image white pixels
points = np.column_stack(np.where(contour.transpose() > 0))
hull_pts = cv2.convexHull(points)

# draw hull on copy of input and on black background
hull = img.copy()
cv2.drawContours(hull, [hull_pts], 0, (0,255,0), 2)
hull2 = np.zeros((hh,ww), dtype=np.uint8)
cv2.drawContours(hull2, [hull_pts], 0, 255, 2)

# get 4 corners from white hull points on black background
num = 4
quality = 0.001
mindist = max(ww,hh) // 4
corners = cv2.goodFeaturesToTrack(hull2, num, quality, mindist)
corners = np.int0(corners)
for corner in corners:
    px,py = corner.ravel()
    cv2.circle(hull, (px,py), 5, (0,0,255), -1)

# get angles to each corner relative to centroid and store with x,y values in list
# angles are clockwise between -180 and +180 with zero along positive X axis (to right)
corner_info = []
center = np.mean(corners, axis=0)
centx = center.ravel()[0]
centy = center.ravel()[1]
for corner in corners:
    px,py = corner.ravel()
    dx = px - centx
    dy = py - centy
    angle = (180/math.pi) * math.atan2(dy,dx)
    corner_info.append([px,py,angle])

# function to define sort key as element 2 (i.e. angle)
def takeThird(elem):
    return elem[2]

# sort corner_info on angle so result will be TL, TR, BR, BL order
corner_info.sort(key=takeThird)

# make conjugate control points
# get input points from corners
corner_list = []
for x, y, angle in corner_info:
    corner_list.append([x,y])
print(corner_list)

# define input points from (sorted) corner_list
input = np.float32(corner_list)

# define output points from dimensions of image, say half of input image
width = ww // 2
height = hh // 2
output = np.float32([[0,0], [width-1,0], [width-1,height-1], [0,height-1]])

# compute perspective matrix
matrix = cv2.getPerspectiveTransform(input,output)

# do perspective transformation setting area outside input to black
result = cv2.warpPerspective(img, matrix, (width,height), cv2.INTER_LINEAR, borderMode=cv2.BORDER_CONSTANT, borderValue=(0,0,0))

# save output
cv2.imwrite('maze_thresh.jpg', thresh)
cv2.imwrite('maze_contour.jpg', contour)
cv2.imwrite('maze_hull.jpg', hull)
cv2.imwrite('maze_rectified.jpg', result)

# Display various images to see the steps
cv2.imshow('thresh', thresh)
cv2.imshow('contour', contour)
cv2.imshow('hull', hull)
cv2.imshow('result', result)
cv2.waitKey(0)
cv2.destroyAllWindows()

形态学后的边缘图像:

在黑色背景上过滤的轮廓:

凸包和输入图像上的4个角点:

透视图偏差的结果:

票数 8
EN

Stack Overflow用户

发布于 2021-05-07 14:55:03

您可以尝试一个简单的阈值来检测迷宫的线条,因为它们很方便地是黑色的:

代码语言:javascript
运行
复制
import cv2

img = cv2.imread("maze.jpg")
gray = cv2.cvtColor(img, cv2.BGR2GRAY)
_, thresh = cv2.threshold(gray, 60, 255, cv2.THRESH_BINARY)
cv2.imshow("Image", thresh)
cv2.waitKey(0)

输出:

您可以使用轨迹栏自己调整阈值:

代码语言:javascript
运行
复制
import cv2

cv2.namedWindow("threshold")
cv2.createTrackbar("", "threshold", 0, 255, id)

img = cv2.imread("maze.jpg")

while True:
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    t = cv2.getTrackbarPos("", "threshold")
    _, thresh = cv2.threshold(gray, t, 255, cv2.THRESH_BINARY)
    cv2.imshow("Image", thresh)
    if cv2.waitKey(1) & 0xFF == ord("q"): # If you press the q key
        break

票数 5
EN

Stack Overflow用户

发布于 2021-05-07 13:22:23

精明是一种边缘探测器。它检测颜色变化的线条。输入图像中的一行有两个这样的转换,每边一个。因此,您可以在图像中的一条线的每一侧看到两条平行线。This answer of mine解释了边和线之间的区别。

因此,您不应该使用边缘检测器来检测图像中的线条。

如果一个简单的阈值不能正确地对此图像进行二值化,请尝试使用一个本地阈值(OpenCV中的“自适应阈值”)。另一件对像这样的图像很有效的事情是应用一个顶帽过滤器(对于这个图像,它将是一个closing(img) - img),其中结构元素被调整到你想要找到的线条的宽度。这将导致图像易于阈值,并将保留所有线比结构元素更薄。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/67434707

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档