1

Below code doesn't draw any line on png image

imgPath = "./images/dummy.png"

img = cv2.imread(imgPath,cv2.IMREAD_UNCHANGED) 
imgBGR = img[:,:,:3] 
imgMask = img[:,:,3]

cv2.line(imgBGR, (200,100), (250,100), (0,100,255), thickness=9, lineType=cv2.LINE_AA)
plt.imshow(imgBGR[:,:,::-1])

On creating copy of BGR channel and using it to draw line works.

imgPath = "./images/dummy.png"

img = cv2.imread(imgPath,cv2.IMREAD_UNCHANGED) 
imgBGR = img[:,:,:3] 
imgMask = img[:,:,3]

imgBGRCopy = imgBGR.copy()

cv2.line(imgBGRCopy , (200,100), (250,100), (0,100,255), thickness=9, lineType=cv2.LINE_AA)
plt.imshow(imgBGRCopy [:,:,::-1])

Please explain why?

Shubham
  • 23
  • 6
  • Have a read about copies and views... https://www.jessicayung.com/numpy-views-vs-copies-avoiding-costly-mistakes/ – Mark Setchell Apr 14 '20 at 20:17
  • @MarkSetchell I do understand that **imgBGR** is a view of **img**. – Shubham Apr 14 '20 at 20:27
  • Does `img.shape` end in `4` and your PNG has an alpha channel whereas a JPEG doesn't? – Mark Setchell Apr 14 '20 at 20:36
  • @MarkSetchell Yes, my png image is having 4 channels(including alpha). First code works with JPEG image after commenting **imgMask = img[:,:,3]** line as it is having only 3 channels. – Shubham Apr 14 '20 at 20:40

1 Answers1

0

For mysterious reason OpenCV fails for draw on a NumPy slice.

See the following post for example: Why cv2.line can't draw on 1 channel numpy array slice inplace?

The error is not related to PNG vs JPEG, or to BGR vs BGRA.
The error is because you are trying to draw on a slice.

For example, the following code also fails:

imgBGR = cv2.imread('test.jpg', cv2.IMREAD_UNCHANGED)
imgB = imgBGR[:,:,0]  # Get a slice of imgBGR
cv2.circle(imgB, (100, 100), 10, 5)

As an alternative, you can draw on the BGRA image.

According to Drawing Functions documentation:

Note The functions do not support alpha-transparency when the target image is 4-channel. In this case, the color[3] is simply copied to the repainted pixels. Thus, if you want to paint semi-transparent shapes, you can paint them in a separate buffer and then blend it with the main image.

The following code is working:

img = cv2.imread(imgPath,cv2.IMREAD_UNCHANGED) 
cv2.line(img, (200,100), (250,100), (0,100,255), thickness=9, lineType=cv2.LINE_AA)

imgBGR = img[:,:,:3] 
plt.imshow(imgBGR[:,:,::-1])

Note:
Python an OpenCV are "Open Source", so in theory we can follow the source code and demystify the problem.

Rotem
  • 30,366
  • 4
  • 32
  • 65