Search code examples
python-3.xopencvroi

Opencv error: (-215:Assertion failed) (mtype == CV_8U || mtype == CV_8S) && _mask.sameSize(*psrc1) in function 'cv::binary_op'


I'm trying to paste a picture on the face detected through a haarcascade.

While I was writing the code, I came across this error..

error: (-215:Assertion failed) (mtype == CV_8U || mtype == CV_8S) && _mask.sameSize(*psrc1) in function 'cv::binary_op'

At first I thought the problem was the size of the mask and the roi wasn't same, so I refered to a same problem on stackoverflow and tried implementing the same on my code and then change it accordingly to my requirements. My aim to paste the desired picture on the roi (which is face in my case), but still the problem persists.

Here is the code..

import cv2
import numpy as np
import imutils

cap=cv2.VideoCapture(0)
classifier= cv2.CascadeClassifier('D:\\Downloads\\Computer-Vision-Tutorial-master\\Computer-Vision-Tutorial-master\\Haarcascades\\haarcascade_frontalface_default.xml')

img=cv2.imread("D:\\Downloads\\anonymous_face_mask.jpg")
rows,cols,channels=img.shape
while(cap.isOpened()):
    img=cv2.imread("D:\\Downloads\\anonymous_face_mask.jpg")
    _,frame=cap.read()

    gray=cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)
    
    img_gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
    ret,original_mask=cv2.threshold(img_gray,100,255,cv2.THRESH_BINARY_INV)
    original_mask_inv=cv2.bitwise_not(original_mask)
    #cv2.imshow("mask_inv",mask_inv)
    face=classifier.detectMultiScale(gray,1.4,5)

    
    for x,y,w,h in face:
        
        face_w = w
        face_h = h
        face_x1 = x
        face_x2 = face_x1 + face_h
        face_y1 = y
        face_y2 = face_y1 + face_h
        img_width=3*face_w
        img_height=int(img_width*rows/cols)

        img_x1=face_x2-int(face_w/2)-int(img_width/2)
        img_x2=face_x1+img_width
        img_y1=face_y2+5
        img_y2=img_y1+img_height

        if img_x1<0:
            img_x1=0
        if img_y1<0:
            img_y1=0
        if img_x2<cols:
            img_x2=cols
        if img_y2<rows:
            img_y2=rows

        imgwidth=img_x2-img_x1
        imgheight=img_y2-img_y1
        if imgwidth<0 or imgheight<0:
            continue

        image=cv2.resize(img,(imgwidth,imgheight),cv2.INTER_AREA)
        mask=cv2.resize(original_mask,(imgwidth,imgheight),cv2.INTER_AREA)
        mask_inv=cv2.resize(original_mask_inv,(imgwidth,imgheight),cv2.INTER_AREA)
        roi=frame[img_y1:img_y2,img_x1:img_x2]
        frame_bg=cv2.bitwise_and(roi,roi,mask=mask)
        img_fg=cv2.bitwise_and(image,image,mask=mask_inv)
        dst=cv2.add(frame_bg,img_fg)
        frame[img_y1:img_y2,img_x1:img_x2]=dst
        cv2.rectangle(frame,(x,y),(x+w,y+h),(0,255,255),2)
        cv2.imshow("framee",frame)
    
    k = cv2.waitKey(1) & 0xff
    if k == ord('q'):
        break
cap.release()
cv2.destroyAllWindows()

Please point out where did I go wrong? Thanks in advance..


Solution

  • I had to run it to find the problem. It is actually that roi is not the same size as the mask all the time... I think it goes "out of bounds" when setting the variable roi, numpy just gives up to the point it can.

    It is hard to know for sure what is wrong, since the code (in my opinion) is a mess. For each face found you calculate several widths and heights which are not needed if you want to simply replace the face found with that of an image and to create a mask of the image.

    Try something like this:

    import cv2
    import numpy as np
    
    # initialize camera, classifier and load the new image
    cap=cv2.VideoCapture(0)
    img=cv2.imread("image.png")
    classifier= cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
    
    # create masks to be used later
    img_gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
    ret,original_mask=cv2.threshold(img_gray,100,255,cv2.THRESH_BINARY_INV)
    original_mask_inv=cv2.bitwise_not(original_mask)
    
    while(cap.isOpened()):
        # get image and find the face(s)
        _,frame=cap.read()
        gray=cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)
        face = classifier.detectMultiScale(gray,1.4,5)
        
        for x,y,w,h in face:
            # resize images and mask to size of the face
            newFace = cv2.resize(img,(w,h),cv2.INTER_AREA)
            mask = cv2.resize(original_mask,(w,h),cv2.INTER_AREA)
            mask_inv = cv2.resize(original_mask_inv,(w,h),cv2.INTER_AREA)
    
            # obtain the foreground of the image and the background of the camera frame
            roi=frame[y:y+h,x:x+w]
            frame_bg=cv2.bitwise_and(roi,roi,mask=mask)
            img_fg=cv2.bitwise_and(newFace,newFace,mask=mask_inv)
    
            # replace the face with the image data and draw a rectangle
            frame[y:y+h,x:x+w]= frame_bg + img_fg
            cv2.rectangle(frame,(x,y),(x+w,y+h),(0,255,255),2)
        
        # show image and wait parse key    
        cv2.imshow("framee",frame)
        k = cv2.waitKey(1) & 0xff
        if k == ord('q'):
            break
    cap.release()
    cv2.destroyAllWindows()
    

    I hope this helps, if not, just leave a comment