【问题标题】:Find vertical 1px lines with OpenCV使用 OpenCV 查找垂直 1px 线
【发布时间】:2021-07-06 13:06:45
【问题描述】:

我有一张类似于下图(左侧)的图片:

我只想提取右侧的红色像素:属于 1px 垂直线的像素,但 到任何较粗的线或具有超过 1 个相邻黑色像素的其他区域。图片是黑白的。

到目前为止,我已经尝试了一个带有垂直(10px,这是我的目的)和水平内核的形态 OPEN 并采取了差异,但这需要一个尴尬的转变并留下一些“斑点”:


    vertical_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (1, 10))
    vertical_mask1 = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, vertical_kernel,
                                      iterations=1)

    horz_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (2, 1))
    horz_mask = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, horz_kernel,
                                      iterations=1)

    M = np.float32([[1,0,-1],[0,1,1]])
    rows, cols = horz_mask.shape
    vertical_mask = cv2.warpAffine(horz_mask, M, (cols, rows))

    result = cv2.bitwise_and(thresh, cv2.bitwise_not(horz_mask))

隔离 1px 线(并且只有 1px 线)的正确方法是什么?

在一般情况下,对于其他内核,这个问题是:如何找到图像中位于内核“适合其内部”的区域中的所有像素(然后进行减法以获得我想要的结果)?

【问题讨论】:

  • 尝试命中或未命中的形态。 docs.opencv.org/master/db/d06/tutorial_hitOrMiss.html
  • 在您的示例图片中,您只有一条像素红线。对于这张图片,您可以逐个像素地进行暴力破解,并且 (1) 将与多个黑色像素相邻的所有红色像素更改为白色,然后 (2) 将所有黑色像素更改为白色。对于更复杂的图片,您必须添加删除所有宽线的第三步。
  • @bfris 红色像素是所需的输出。

标签: opencv mathematical-morphology straight-line-detection


【解决方案1】:

基本上是(二进制)template matching。您需要从您的“内核”派生适当的模板。对于较大的“内核”,可能还需要为这些模板使用掩码,参见。 cv2.matchTemplate.

单像素垂直线最重要的特征是什么?当前像素的左右邻居必须是0。所以,要匹配的模板是[0, 1, 0]。通过使用TemplateMatchModecv2.TM_SQDIFF_NORMED,完美匹配将导致result 数组中的0 值接近。

您可以屏蔽这些位置,并根据模板的大小进行扩展。然后,您使用bitwise_and 提取属于您的模板的实际像素。

这是一些带有一些模板(“内核”)的代码:

import cv2
import numpy as np

img = cv2.imread('AapJk.png', cv2.IMREAD_GRAYSCALE)[:, :50]

vert_line = np.array([[0, 1, 0]], np.uint8)
cross = np.array([[0, 1, 0], [1, 1, 1], [0, 1, 0]], np.uint8)
corner = np.array([[0, 0, 1], [0, 0, 1], [1, 1, 1]], np.uint8)

for i_k, k in enumerate([vert_line, cross, corner]):
    m, n = k.shape
    img_tmp = 1 - img // 255
    mask = cv2.matchTemplate(img_tmp, k, cv2.TM_SQDIFF_NORMED) < 10e-6
    mask = cv2.dilate(mask.astype(np.uint8), np.ones((m, n)), anchor=(n-1, m-1))
    m, n = mask.shape
    mask = cv2.bitwise_and(img_tmp[:m, :n], mask)
    out = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
    roi = out[:m, :n]
    roi[mask.astype(bool), :] = [0, 0, 255]
    cv2.imwrite('{}.png'.format(i_k), out)

垂直线:

交叉:

右下角3 x 3:

较大的模板(“内核”)很可能需要额外的掩码,具体取决于应考虑多少或哪些相邻像素。

----------------------------------------
System information
----------------------------------------
Platform:      Windows-10-10.0.19041-SP0
Python:        3.9.1
PyCharm:       2021.1.3
NumPy:         1.20.3
OpenCV:        4.5.2
----------------------------------------

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-02
    • 2014-09-21
    • 2012-12-28
    • 1970-01-01
    • 1970-01-01
    • 2017-08-23
    相关资源
    最近更新 更多