img data type = 17 is not supported

Ive got a video which ive im trying to show a specific region using cv2.polyfill and bitwise operation. When I do this on a image it works fine but when done on a video it comes up with the following error. Ive had no problems doing this earlier on with another picture/video. The region to be shown does show up as a frozen picture but also crashes the kernel. The code is:

import cv2
import numpy as np
   cap = cv2.VideoCapture("heartvideo.wmv",0)

def roi(frame): 
  mask = np.zeros_like (frame)
  array = np.array([[148,550],[300,650],[400,680],[800,680],[880,560],[555,70],[492,50]])
  contours = np.array([[50,50], [50,150], [150,150], [150,50]])
  cv2.fillPoly(mask, pts = [array], color =(255))
  masked = cv2.bitwise_and(mask,frame)
  return mask


while(cap.isOpened()): # while video is initialised
  ret, frame = cap.read() #reads the video bit by bit
  adj = roi(frame)
 
  if ret:
    cv2.imshow("Image", adj)
  else:
    cap.set(cv2.CAP_PROP_POS_FRAMES, 0)

  if cv2.waitKey(15) & 0xFF == ord('q'):
    break


cap.release()
cv2.destroyAllWindows()

error: OpenCV(4.5.3) :-1: error: (-5:Bad argument) in function ‘fillPoly’

Overload resolution failed:

  • img data type = 17 is not supported
  • Expected Ptr<cv::UMat> for argument ‘img’

Answer

The issue is that you’re using a 3-channel BGR mask (datatype 17 is a 3-channel image). You used np.zeros_like(frame) to set your mask which means that it’ll have the exact same dimensions as the image you passed in. If you meant for it to be a 1-channel image you should set the dimensions.

I’m not sure what version of OpenCV you’re using and I can’t replicate the error with OpenCV 4.4. On this version it allows a 3-channel image even if you’ve specified a 1-channel color as the fillPoly argument though it does this by assuming you meant (255,0,0) for the color. It could be that on a different version of OpenCV the color dimensions had to match the image dimensions and it’s complaining about that.

Try out this revised version of the code and see if it works.

import cv2
import numpy as np

def roi(frame): 
  # draw a polygon on mask
  height,width = frame.shape[:2];
  mask = np.zeros((height, width), np.uint8);
  array = np.array([[148,550],[300,650],[400,680],[800,680],[880,560],[555,70],[492,50]])
  contours = np.array([[50,50], [50,150], [150,150], [150,50]])
  cv2.fillPoly(mask, pts = [array], color =(255))

  # mask stuff on frame
  # masked = cv2.bitwise_and(mask,frame)
  copy = np.zeros_like(frame);
  copy[mask == 255] = frame[mask == 255];
  return copy;

# open video
cap = cv2.VideoCapture("heartvideo.wmv", 0);

while(cap.isOpened()): # while video is initialised
  ret, frame = cap.read() #reads the video bit by bit
 
  if ret:
    adj = roi(frame)
    cv2.imshow("Image", adj)
  else:
    cap.set(cv2.CAP_PROP_POS_FRAMES, 0)

  if cv2.waitKey(15) == ord('q'):
    break

cap.release()
cv2.destroyAllWindows()