使用 OpenCV 查找垂直 1px 线

问题描述

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

enter image description here

我只想提取右侧的红色像素:属于 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,horz_kernel,iterations=1)

    M = np.float32([[1,-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 线)的正确方法是什么?

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

>

解决方法

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

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

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

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

import cv2
import numpy as np

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

vert_line = np.array([[0,0]],np.uint8)
cross = np.array([[0,0],[1,1],[0,np.uint8)
corner = np.array([[0,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,255]
    cv2.imwrite('{}.png'.format(i_k),out)

竖线:

Vertical line

交叉:

Cross

右下角 3 x 3

Bottom right corner

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

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

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...