Python OpenCV face detection code sometimes raises `'tuple' object has no attribute 'shape'`

前端 未结 4 941
花落未央
花落未央 2020-12-21 21:54

I am trying to build a face detection application in python using opencv.
Please see below for my code snippets:

 # Loading the Haar Cascade Classifier
c         


        
相关标签:
4条回答
  • 2020-12-21 22:36

    To get the number of faces it should be:

    print "Number of faces found in-> ", img_fname, " are ", len(faces).

    I would also recommend that to convert image to gray scale you should write:

    gray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY) instead of gray = cv2.cvtColor(im, cv2.COLOR_RGB2GRAY) as color images are loaded by openCV in BGR mode.

    0 讨论(0)
  • 2020-12-21 22:44

    The cause of the problem is that detectMultiScale returns an empty tuple () when there's no matches, but a numpy.ndarray when there are matches.

    >>> faces = classifier.detectMultiScale(cv2.imread('face.jpg'))
    >>> print(type(faces), faces)
    <class 'numpy.ndarray'> [[ 30 150  40  40]] 
    
    >>> faces = classifier.detectMultiScale(cv2.imread('wall.jpg'))
    >>> print(type(faces), faces)
    <class 'tuple'> ()
    

    You might expect that a negative result would be a ndarray of shape (0,4), but that's not the case.

    This behaviour and the reasoning behind it is not explained in the documentation, which instead indicates that the return value should be "objects".

    OpenCV has a lot of warts like this, and the cryptic error messages doesn't help. One way deal with it is to add logging statements or asserts into your code to check that everything is the type you expected.

    It's also very useful to explore how a library works in a repl such as ipython. This is used in Rahul K P's answer.

    In this case, you can solve your problem by not using shape. Python has many data types that are sequences or collections, for example tuple, list and dict. All of these implement the len() built-in function and you can also loop over them using for x in y. In contrast shape is only a property of numpy.ndarray, and not found in any of the built-in python data types.

    Your code should work if you rewrite it to use len(faces) instead of faces.shape[0], since the former works with both tuple and ndarray.

    for img_fname in os.listdir('/home/work/images/caltech_face_dataset/'):
        img_path = '/home/work/images/caltech_face_dataset/' + img_fname
        im = imread(img_path)
        gray = cv2.cvtColor(im, cv2.COLOR_RGB2GRAY)
        faces = faceCascade.detectMultiScale(gray)  # use the grayscale image
        print "Number of faces found in-> {} are {}".format(
            img_fname, len(faces))  # len() works with both tuple and ndarray
        num_faces_dict[img_fname] = len(faces)
        # when faces is (), the following loop will never run, so it's safe.
        for (x,y,w,h) in faces: 
            cv2.rectangle(im, (x,y), (x+w,y+h), (255,255,255), 3)
        rect_img_path = '/home/work/face_detected/rect_' + img_fname
        cv2.imwrite(rect_img_path,im)
    
    0 讨论(0)
  • 2020-12-21 22:45

    From your error understand that you are trying to read the shape. But shape is the attribute of numpy.ndarray. You are trying to read the shape from the result of face detection. But that will only return the position only. Look at the types. Here img is an image and faces is the result of face detection. I hope you got the problem.

    Updated with full code. For more clarification

    In [1]: import cv2
    In [2]: cap = cv2.VideoCapture(0)
    In [3]: ret,img = cap.read()
    In [4]: cascadePath = "/home/bikz05/Desktop/SNA_work/opencv-2.4.9/data/haarcascades/haarcascade_frontalface_default.xml"
    In [5]: faceCascade = cv2.CascadeClassifier(cascadePath) 
    In [6]: faces = faceCascade.detectMultiScale(img)
    In [7]: type(img)
    Out[1]: numpy.ndarray
    In [8]: type(faces)
    Out[2]: tuple
    

    Look at the diffrence.

    In [9]: img.shape
    Out[3]: (480, 640, 3)
    In [10]: faces.shape
    ---------------------------------------------------------------------------
    AttributeError                            Traceback (most recent call last)
    <ipython-input-40-392225a0e11a> in <module>()
    ----> 1 faces.shape
    AttributeError: 'tuple' object has no attribute 'shape'
    

    If you want the number of faces. It's in the form of list of tuple. You can find the number of faces using len like len(faces)

    0 讨论(0)
  • 2020-12-21 22:49
    import numpy as np 
    import cv2
    
    face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
    image = cv2.imread('myfriends.jpg')
    grayImage = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    faces = face_cascade.detectMultiScale(grayImage)
    print ("Number of faces detected: " + str(faces.shape[0]))
    for (x,y,w,h) in faces:
        cv2.rectangle(image,(x,y),(x+w,y+h),(0,255,0),1) 
    cv2.rectangle(image, ((0,image.shape[0] -25)),(270, image.shape[0]), (255,255,255), -1) 
    cv2.putText(image, "Number of faces detected: " + str(faces.shape[0]), (0,image.shape[0] -10), cv2.FONT_HERSHEY_TRIPLEX, 0.5, (0,0,0), 1)
    cv2.imshow('Image with faces',image)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    
    0 讨论(0)
提交回复
热议问题