1

I am building a game with openCV and pygame. When I test code, it sometimes works and sometimes returns an error saying

line 76, in "face_recognition.py"

self.dets = self.detector(self.frame, 0)

TypeError: __call__(): incompatible function arguments. The following argument types are supported:
    1. (self: dlib.fhog_object_detector, image: array, upsample_num_times: int=0) -> dlib.rectangles

I think it means the self.frame is empty but why does it sometimes work and some times not? How should I fix this problem?

This is the class of the face recognition.

class face():
def __init__(self,game,screen):
    super().__init__()
    self.game=game
    self.screen=screen

    self.cap = cv2.VideoCapture(0)
    self.fourcc = cv2.VideoWriter_fourcc(*'XVID')
    self.predictor_path = 'shape_predictor_81_face_landmarks.dat'
    self.detector = dlib.get_frontal_face_detector() #INITIALIZE FACE PROTECTOR
    self.predictor = dlib.shape_predictor(self.predictor_path) #LANDMARK PREDICTO

    self.cap.set(3,160) #self.
    self.cap.set(4,120) 
    self.color=False#True#False

    (self.mStart,self.mEnd)=(48,54) #mouth
    self.MOUTH_AR_THRESH = 0.1

    self.direction = 0 #direction of eyebrows 
    # grab the indexes of the facial landmarks for the left and
    # right eyebrows, respectively
    (self.lbStart, self.lbEnd) = face_utils.FACIAL_LANDMARKS_IDXS["left_eyebrow"]
    (self.rbStart, self.rbEnd) = face_utils.FACIAL_LANDMARKS_IDXS["right_eyebrow"]

    #Get the indexes of the nose line
    (self.nStart, self.nEnd) = face_utils.FACIAL_LANDMARKS_IDXS["nose"]

    #Get the mid indexes of the facial landmarks
    self.lbMid = int((self.lbStart + self.lbEnd)/2)
    self.rbMid = int((self.rbStart +self.rbEnd)/2)
    self.nMid = int((self.nStart + self.nEnd)/2)

    # Define variables that will contain the euclidean distances
    self.rightEyebrowToNose = 0
    self.leftEyebrowToNose = 0

def __call__(self):
    print (" ")

def getDirection(self):
    return self.direction

def defineDirection(self,direction):
    self.direction = direction

def face_recognition(self,screen):
    self.ret,self.frame = self.cap.read() 
    self.frame = cv2.flip(self.frame, 1)

    self.dets = self.detector(self.frame, 0) #rects
    self.cvToPygame=cv2.cvtColor(self.frame,cv2.COLOR_BGR2RGB)
    if not self.color:
        self.cvToPygame=cv2.cvtColor(self.cvToPygame,cv2.COLOR_BGR2GRAY)
        self.cvToPygame=cv2.cvtColor(self.cvToPygame,cv2.COLOR_GRAY2RGB)
    self.cvToPygame=np.rot90(self.cvToPygame)

    self.cvToPygame=pygame.surfarray.make_surface(self.cvToPygame)
    self.screen.blit(self.cvToPygame,(0,0))

    for k, d in enumerate(self.dets):
        shape = self.predictor(self.frame, d)
        landmarks = np.matrix([[p.x, p.y] for p in shape.parts()])
        for num in range(shape.num_parts):
            cv2.circle(self.frame, (shape.parts()[num].x, shape.parts()[num].y), 3, (0,255,0), -1)
        A=dist.euclidean((shape.parts()[61].x,shape.parts()[61].y),(shape.parts()[67].x,shape.parts()[67].y))
        B=dist.euclidean((shape.parts()[63].x,shape.parts()[63].y),(shape.parts()[65].x,shape.parts()[65].y))
        C=dist.euclidean((shape.parts()[48].x,shape.parts()[48].y),(shape.parts()[54].x,shape.parts()[54].y))
        mar=(A+B)/(2.0*C)
        mar=round(mar,5)


        if mar>self.MOUTH_AR_THRESH:
            #cv2.putText(self.frame,"MOUTH IS OPEN!",(30,60),cv2.FONT_HERSHEY_SIMPLEX,0.7,(0,0,255),2)
            print("mouth is open")
            return True
        else:
            print("closed")
            return False

    self.cap.release()
    cv2.destroyAllWindows()

def distance(A, B):
    (ax,ay) = A
    (bx,by) = B
    return math.sqrt((ax-bx)**2 + (ay-by)**2)

def eyebrowDetection(self,screen):

    for k, d in enumerate(self.dets):
        shape = self.predictor(self.frame, d)
        shape = face_utils.shape_to_np(shape)
        # Get the positions of the
        leftEyebrowCoordinates = shape[self.lbMid]
        rightEyebrowCoordinates = shape[self.rbMid]
        currentNosePosition = midPointNoseCoordinates = shape[self.nMid]
        midPointNoseCoordinates = shape[self.nMid]

        currentRightEyebrowDistance = dist.euclidean(rightEyebrowCoordinates,midPointNoseCoordinates)
        currentLeftEyebrowDistance =dist.euclidean(leftEyebrowCoordinates,midPointNoseCoordinates)

        if (self.rightEyebrowToNose == 0) or (self.leftEyebrowToNose == 0):
            self.rightEyebrowToNose =dist.euclidean(rightEyebrowCoordinates,midPointNoseCoordinates)
            self.leftEyebrowToNose = dist.euclidean(leftEyebrowCoordinates,midPointNoseCoordinates)
        elif (currentRightEyebrowDistance > self.rightEyebrowToNose) or (currentLeftEyebrowDistance >  self.leftEyebrowToNose):
            self.defineDirection(1)
            print ("[RESULT] UP")
            return True
        else:
            self.defineDirection(-1)
            print ("[RESULT] DOWN")
            return False

The below is how I call the functions in main.

  def main(self):
      face=face_recog.face(self,self.screen)
                ....
       while True:
            mouthOpen=face.face_recognition(self.screen)
            eyebrow=face.eyebrowDetection(self.screen)


            while buttonPressed==2:
                buttonPressed=gameover_.pausePressed()
                if buttonPressed==1:
                    self.gameover=True
                break


        self.player.update(self,self.up,self.down,self.left, self.right)
        self.camera.update()
        pygame.display.flip()

Please help me solve the problem.

Regina Kang
  • 135
  • 2
  • 11
  • Please post the full traceback properly formatted. – a_guest Dec 12 '19 at 11:53
  • I edited it with all the info related to face_recog.py – Regina Kang Dec 12 '19 at 12:33
  • Well that's not the full traceback. Try wrapping that call in `try: ... except TypeError: print(type(self.frame), self.frame)` or `breakpoint()` or something similar and inspect the function argument for the cases where it failed. That might give you a conclusion about the problem. – a_guest Dec 12 '19 at 14:44
  • 1
    I got to find out that using cv2.VideoCapture was the problem. For some reason it returned an empty frame. So I changed it to VideoStream(0).start() function and self.frame=self.videoStream.read(). That solved my problem. – Regina Kang Dec 16 '19 at 05:28
  • @ReginaKang Please post this comment as an answer. It is fine to answer your own question. Others may find this helpful. (Maybe I'll upvote it) – Rabbid76 Dec 19 '20 at 09:38

0 Answers0