使用opencv将曲线规范化成矩形

3

我有一台水下相机,可以检测到PVC框架,如图1所示。我添加了随机的在线水效果,以便在预期的恶劣条件下积累。

我尝试了两种方法:

  • Canny边缘算法。

  • 多个颜色转换、平滑和阈值处理。

后者的结果是最有效的。

我的问题是我很难为进一步处理准备这个结果。

为了更容易地处理,结果需要呈线条形状,并具有恒定的宽度,就像右侧部分那样。

我尝试使用概率霍夫线变换来检测任何线条,但它们都太弯曲而无法被检测到。


“规范化的结果是指所有形状都是具有恒定宽度的统一矩形形状。”这并不是一个有用的定义,因为任何图像都可以符合这个定义:一张图片是由像素构成的,而单个像素是一个矩形形状。” - Julien
@Julien 我指的是图像中检测到的对象作为结果。 - omarec14
我的评论仍然适用。任何检测到的形状,无论多么扭曲,最终都是由矩形像素组成的。换句话说,你的问题定义不清。你需要确定你的“矩形”的“比例”或“粒度”。 - Julien
1
@Julien,图像由矩形像素组成是常识。我的问题仅在于消除所有抖动并获得线条形状的对象。但是,我将编辑问题以更清楚地阐明。 - omarec14
再次强调,“wiggle”可能在你的脑海中有明确的定义,但它是一个模糊的概念。你目前的定义并不排除我告诉你你的图像不是“wiggly”的可能性。因此,如果这个答案不能满足你,你需要想出一个明确定义你想要的东西的定义。 - Julien
1
@Julien 图片已经添加以澄清。 - omarec14
1个回答

1
为了从图像中提取线条,您可以在阈值化后过滤水平和垂直线条,并通过中心绘制具有恒定宽度的矩形,然后删除交叉点周围的小对象。
import cv2
import numpy as np
from skimage.io import imread
from skimage.morphology import remove_small_objects

rgb = imread('https://istack.dev59.com/QPz8W.webp')
# convert to HSV for thresholding
hsv = cv2.cvtColor(rgb, cv2.COLOR_RGB2HSV)

# threshold hue channel for purple tubes, value channel for blue tubes
thresh_hue = cv2.threshold(hsv[..., 0], 127, 255, cv2.THRESH_BINARY)[1]
thresh_val = cv2.threshold(hsv[..., 2], 200, 255, cv2.THRESH_BINARY)[1]

# combine purple tubes with blue tubes
thresh = thresh_hue | thresh_val

cv2.imwrite('threshold_result.png', thresh)

# morphologically close the gaps between purple and blue tubes
thresh = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, np.ones((5, 5), np.uint8))

cv2.imwrite('closing_result.png', thresh)

# morphological opening with horizontal and vertical kernels
h_kernel = np.zeros((11, 11), dtype=np.uint8)
h_kernel[5, :] = 1

v_kernel = np.zeros((11, 11), dtype=np.uint8)
v_kernel[:, 5] = 1

h_tubes = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, h_kernel, iterations=6)
v_tubes = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, v_kernel, iterations=7)

cv2.imwrite('horizontal_tubes.png', h_tubes)
cv2.imwrite('vertical_tubes.png', v_tubes)

# find contours and draw rectangles with constant widths through centers
h_contours = cv2.findContours(h_tubes, cv2.RETR_LIST,
                              cv2.CHAIN_APPROX_SIMPLE)[0]
h_lines = np.zeros(thresh.shape, np.uint8)

for cnt in h_contours:
    x, y, w, h = cv2.boundingRect(cnt)
    y += int(np.floor(h / 2) - 4)
    cv2.rectangle(h_lines, (x, y), (x + w, y + 8), 255, -1)

v_contours = cv2.findContours(v_tubes, cv2.RETR_LIST,
                              cv2.CHAIN_APPROX_SIMPLE)[0]
v_lines = np.zeros(thresh.shape, np.uint8)

for cnt in v_contours:
    x, y, w, h = cv2.boundingRect(cnt)
    x += int(np.floor(w / 2) - 4)
    cv2.rectangle(v_lines, (x, y), (x + 8, y + h), 255, -1)

# combine horizontal and vertical lines
all_lines = h_lines | v_lines

cv2.imwrite('all_lines.png', all_lines)

# remove small objects around the intersections
xor = np.bool8(h_lines ^ v_lines)
removed = xor ^ remove_small_objects(xor, 350)

result = all_lines & ~removed * 255

cv2.imwrite('result.png', result)

threshold_result.png

threshold_result

closing_result.png

closing_result

horizontal_tubes.png

horizontal_tubes

vertical_tubes.png

vertical_tubes

all_lines.png

all_lines

result.png

result


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接