传统的线宽确定方法是通过距离变换。这是一种计算每个前景像素到背景的距离的算法。该距离沿线的中心最大,并且是线宽度的一半。
因为你的线是近似垂直的,所以我们可以只取每个图像行距离变换的最大值。这些值的平均值大约是平均宽度。
如果沿每行(或列)取最大值不会沿线的中心线产生良好的采样,则需要更复杂的算法来提取沿该中心线的值。
我这里使用DIPlib进行演示,其他库也会有距离变换。 [免责声明:我是 DIPlib 的作者。]
import diplib as dip
import numpy as np
img = dip.ImageRead('UVduo.png')
img = img > 128
dt = dip.EuclideanDistanceTransform(img)
width = dip.Maximum(dt, process=[True, False])
print(2 * np.mean(width))
这会输出
15.26
,即以像素为单位的平均宽度。
如果你假设你的线的中轴代表你的线的宽度为一个像素,那么如果你的中轴由 N 个像素组成,但你的实际线由 3N 个像素组成,你可以说这是一个 “相当合理” 假设你的线是 3 像素宽。
#!/usr/bin/env python3
import cv2 as cv
import numpy as np
from skimage.morphology import medial_axis
# Load image and threshold
im = cv.imread("line.png", cv.IMREAD_GRAYSCALE)
_, thr = cv.threshold(im,127,255,cv.THRESH_BINARY)
# Count white pixels
nWhite = np.count_nonzero(thr)
# Get medial axis of white line and line length
skeleton = (medial_axis(thr*255)).astype(np.uint8)
nMedial = np.count_nonzero(skeleton)
cv.imwrite('DEBUG-skeleton.png',(skeleton*255).astype(np.uint8))
# Calculate average thickness
aveThickness = nWhite / nMedial
print(f'{aveThickness=}, {nWhite=}, {nMedial=}')
输出
aveThickness=18.186858316221766, nWhite=8857, nMedial=487
根据您提供的其他答案,如果我没记错的话,您所需要的只是行间的宽度。为此,您只需在行上执行一个简单的
np.sum
操作,然后除以 255(假设它是一个仅包含 0 和 255 值的掩码)。这将为您提供每行的宽度。
# assuming mask is the image with shape WxHx1 having values 0 and 255
res = np.sum(mask, axis=1) / 255
在您提供的顶部图像上执行此操作,得到的平均宽度为 18.84,值范围在 12 到 25 之间。