Python OpenCV 人脸检测代码有时会引发“元组”对象没有属性“形状”

Posted

技术标签:

【中文标题】Python OpenCV 人脸检测代码有时会引发“元组”对象没有属性“形状”【英文标题】:Python OpenCV face detection code sometimes raises `'tuple' object has no attribute 'shape'` 【发布时间】:2016-10-12 04:40:42 【问题描述】:

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

 # 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: 'tuple' 对象没有属性 'shape'

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

【问题讨论】:

不要张贴图片和链接到您的问题,在您的问题中发布代码和问题此处 我已经发布了代码..不知道发布图片和链接到问题是不允许的。请不要对这个问题投反对票。 @Maddy 并不是不允许这样做 - 而是我的人不登录 Stack Overflow 然后去点击其他网站的链接,看看你的问题是什么。将代码复制/粘贴到您的问题中需要几秒钟的时间,因此如果您没有努力提出问题 - 人们不会付出任何努力来回答。 感谢@Macro Man。我得到了它。下次我发布任何问题时会记住您的建议。 我还编辑了您的帖子以更正格式 - 您可以学习如何使用降价语法by visiting this page 【参考方案1】:

问题的原因是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,但事实并非如此。

这种行为及其背后的原因是not explained in the documentation,它表示返回值应该是“objects”。

OpenCV 有很多这样的缺点,而且神秘的错误消息也无济于事。处理它的一种方法是将日志语句或断言添加到您的代码中,以检查所有内容是否符合您的预期。

探索库在诸如 ipython 之类的 repl 中的工作方式也非常有用。这用于Rahul K P's answer。

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

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

【讨论】:

【参考方案2】:

根据您的错误了解您正在尝试阅读shape。但是shape 是numpy.ndarray 的属性。您正在尝试从人脸检测结果中读取形状。但这只会返回位置。看类型。这里img 是一张图片,faces 是人脸检测的结果。我希望你有问题。

已更新完整代码。如需更多说明

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

看看差异。

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'

如果你想要面数。它是元组列表的形式。您可以使用len 找到人脸数量,例如len(faces)

【讨论】:

但是为什么代码对大多数图像都可以正常工作并且仅在某些图像上引发错误。 docs.scipy.org/doc/numpy-1.10.1/reference/arrays.ndarray.htmlnumpy.ndarry的文档。 @RahulKP:我看到您使用的是 opencv 2.4.9。我使用 3.0 版,结果DetectMultiScale 将返回一个空的tuple(无匹配)或ndarray(找到匹配)。 2.4版也一样吗?我在my answer 中提供了更多详细信息。 @HåkenLid 感谢您提供宝贵的信息。我给了你一票。【参考方案3】:

要获得面数应该是:

print "Number of faces found in-&gt; ", img_fname, " are ", len(faces).

我还建议您将图像转换为灰度:

gray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY) 而不是 gray = cv2.cvtColor(im, cv2.COLOR_RGB2GRAY),因为 openCV 在 BGR 模式下加载彩色图像。

【讨论】:

您对BGRRGB 的看法是对的。但在这种情况下,它应该没有任何区别,因为灰度转换只是平均三个通道。 detectMultiScale返回一个列表是不正确的。它返回一个 ndarray 或一个空元组。

以上是关于Python OpenCV 人脸检测代码有时会引发“元组”对象没有属性“形状”的主要内容,如果未能解决你的问题,请参考以下文章

OpenCV-Python实战(14)——人脸检测详解(仅需6行代码学会4种人脸检测方法)

OpenCV + Python 人脸检测

Python-opencv学习第三十课:人脸检测

Python+OpenCV 简单实现人脸检测多个和人脸识别 2(附代码)

基于Opencv-python人脸口罩检测(附完整代码)

基于Opencv-python人脸口罩检测(附完整代码)