When specifying a line thickness greater than 1, the resulting line width drawn by cv2.line() is wider than specified. Specifying a thickness of 1,2,3,4,5,6 produces a line width of 1,3,5,5,7,7 respectively. I have tried using different lineType values (4,8,16) and sub-pixel point locations with the shift parameter with no effect on the line width. Am I doing something wrong?
For example:
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)
produces:
[[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]]
Your question is a simple one, and the answer is a simple one, as well: No, you are not doing anything wrong. The implementation of the line drawing in OpenCV seems to be quite basic.
I tried this with several line widths and also with fractional starting and ending positions. The line width parameter does not really work. The simple Brezenham lines (single-pixel lines from integer pixel positions) are fine, but the thicker lines are not good.
See this test code:
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)
What you get is this:
The line thickness depends heavily on the angle; diagonal lines are much thicker than horizontal or vertical lines. Also, the thickness of the lines is anyway wrong (3 at thinnest) as you noticed. Using anti-alias does not make a significant change.
However, if this is done with fractional coordinates, the thickness variation is smaller (but the thickness is still wrong):
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)
Also, the problem seems to vanish with thick lines (thickness set to 5, real thickness 7, no fractional coordinates). This suggest that the rotation-dependent error is additive:
Then let's try to draw overlapping files with widths 10, 11, and 12 with different shades of gray:
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)
In principle there should be three colours seen, but in practice only two are visible. This means that the lines with widths 11 and 12 are drawn with the same width (13). Any tricks with the fractional coordinates produce the same result.
Summary: Only odd line widths are available. Narrow lines have large relative width errors if fractional (shifted) coordinates are not used. If you need to have more control, draw thicker line at a higher resolution and then downsample. (Clumsy, I know.)
The tests above have been carried ouy with OpenCV version 2.4.9.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With