Python OpenCV 画线宽度

5
当指定线条粗细大于1时,cv2.line()绘制的结果线宽比指定的要宽。分别指定1、2、3、4、5、6的粗细会得到线宽为1、3、5、5、7、7。我尝试使用不同的lineType值(4、8、16)和带有shift参数的亚像素点位置,但对线宽没有影响。我做错了什么吗?
例如:
import numpy as np
import cv2

a = np.zeros((10,10), dtype=np.uint8)
cv2.line(a, (0,4), (9,4), 1, 2)
print(a)

生成:

 [[0 0 0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0 0 0]
 [1 1 1 1 1 1 1 1 1 1]
 [1 1 1 1 1 1 1 1 1 1]
 [1 1 1 1 1 1 1 1 1 1]
 [0 0 0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0 0 0]]
1个回答

8

你的问题很简单,答案也很简单:不,你没有做错任何事情。OpenCV中的线条绘制实现似乎相当基础。

我尝试了几种线宽以及分数起始和结束位置。线宽参数并不能真正发挥作用。简单的Brezenham线(从整数像素位置开始的单像素线)是好的,但较粗的线不好。

请参考以下测试代码:

import numpy as np
import cv2

a = np.zeros((200,200),dtype=np.uint8)
for u in np.exp(np.linspace(0,1j*2*np.pi,25)):
    cv2.line(a, (100, 100), (int(100+100*u.real+.5), int(100+100*u.imag+.5)), 255, 2)
cv2.imwrite('lines.png', a)

你会得到以下内容:
图片链接:https://istack.dev59.com/x8FpI.webp 线条的粗细在很大程度上取决于角度,对角线比水平或垂直线更粗。此外,正如您所注意到的那样,线条的粗细本来就是错误的(最薄处为3)。使用反锯齿不会有显着改变。
然而,如果使用分数坐标进行操作,则线条的厚度变化较小(但仍然存在错误的厚度)。
import numpy as np
import cv2

a = np.zeros((200,200),dtype=np.uint8)
for u in np.exp(np.linspace(0,1j*2*np.pi,25)):
    cv2.line(a, (1600, 1600), (int(1600+1600*u.real+.5), int(1600+1600*u.imag+.5)), 255, 2, shift=4)
cv2.imwrite('lines_shift.png', a)

enter image description here

此外,问题似乎会随着线条加粗而消失(厚度设置为5,实际厚度为7,没有小数坐标)。这表明旋转依赖误差是可加的:

enter image description here

接下来,让我们尝试用不同灰度的宽度10、11和12绘制重叠的文件:

import numpy as np
import cv2

a = np.zeros((200,200),dtype=np.uint8)
for u in np.exp(np.linspace(0,1j*2*np.pi,25)):
    cv2.line(a, (100, 100), (int(100+100*u.real+.5), int(100+100*u.imag+.5)), 255, 12)
    cv2.line(a, (100, 100), (int(100+100*u.real+.5), int(100+100*u.imag+.5)), 128, 11)
    cv2.line(a, (100, 100), (int(100+100*u.real+.5), int(100+100*u.imag+.5)), 64, 10)
cv2.imwrite('lines_variation.png', a)

enter image description here

原则上应该有三种颜色,但实际上只能看到两种颜色。这意味着宽度为11和12的线条使用相同的宽度(13)绘制。任何带有分数坐标的技巧都会产生相同的结果。

总结:仅有奇数线宽可用。如果不使用分数(偏移)坐标,则窄线的相对宽度误差较大。如果需要更多的控制,则可以在更高的分辨率下绘制较厚的线条,然后进行下采样。(笨拙,我知道。)

以上测试是使用OpenCV版本2.4.9进行的。


这正是我所怀疑的。感谢您提供如此详尽的答案。不幸的是,我需要精确控制线宽。您有其他推荐的绘图库吗?OpenCV的吸引力在于其简单性。我看了Pycairo,但似乎对我的需求来说有些过重了。 - Brian Trotter
然后你可以尝试使用PILPillow来满足你的需求。然后再做一些工作,你可能能够让aggdraw做你想要的事情。它实际上是为这种工作而创建的,但不幸的是,它没有以易于安装的形式进行积极维护。请参见:https://bitbucket.org/2degrees/aggdraw-64bits/src - DrV

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