Python OpenCV人脸检测代码有时会引发'tuple'对象没有属性'shape'`

发布于 2021-01-29 15:02:26

我正在尝试使用opencv在python中构建人脸检测应用程序。
请参阅下面的代码段:

 # Loading the Haar Cascade Classifier
cascadePath = "/home/work/haarcascade_frontalface_default.xml"
faceCascade = cv2.CascadeClassifier(cascadePath)

# Dictionary to store image name & number of face detected in it
num_faces_dict = {}

# Iterate over image directory. 
# Read the image, convert it in grayscale, detect faces using HaarCascade Classifier
# Draw a rectangle on the image

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(im)
    print "Number of faces found in-> ", img_fname, " are ", faces.shape[0]
    num_faces_dict[img_fname] = faces.shape[0]
    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)

此代码对于大多数图像都适用,但是对于其中的某些图像则会引发错误-

AttributeError:“元组”对象没有属性“ shape”
在此处输入图片说明

在打印面数的行中出现错误。任何帮助,将不胜感激。

关注者
0
被浏览
120
1 个回答
  • 面试哥
    面试哥 2021-01-29
    为面试而生,有面试问题,就找面试哥。

    问题的原因是当没有匹配项时detectMultiScale返回一个空的元组(),而numpy.ndarray在有匹配项时返回一个空的元组。

    >>> 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'> ()
    

    您可能期望负结果将是形状为(0,4)的ndarray,但事实并非如此。

    该行为及其背后的原因未在文档中进行说明,而是指示返回值应为“对象”。

    OpenCV有很多这样的疣,而隐秘的错误消息也无济于事。处理它的一种方法是在代码中添加日志记录语句或断言,以检查所有内容是否都是您期望的类型。

    探索库如何在诸如 ipython之类 的repl中工作是非常有用的。这在Rahul
    KP的答案中使用

    在这种情况下,您可以不使用来解决您的问题shape。Python有那些序列或集合,例如许多的数据类型tuplelistdict。所有这些都实现了len()内置功能,您也可以使用循环它们for x in y。相反,shape它只是的一个属性numpy.ndarray,在任何内置的python数据类型中都找不到。

    如果您将代码重写为uselen(faces)而不是,则您的代码应该可以工作faces.shape[0],因为前者可同时用于tuple和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)
    


知识点
面圈网VIP题库

面圈网VIP题库全新上线,海量真题题库资源。 90大类考试,超10万份考试真题开放下载啦

去下载看看