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

问题描述 投票:0回答:4

我正在尝试使用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:'tuple'对象没有属性'shape'enter image description here

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

python opencv face-detection
4个回答
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'> ()

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

这种行为及其背后的推理是not explained in the documentation,它反而表明返回值应该是“对象”。

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)

1
投票

从您的错误中了解到您正在尝试阅读shape。但shapenumpy.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)找到面数


1
投票

要获得面数,它应该是:

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

我还建议您将图像转换为灰度,您应该写:

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


0
投票
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()
© www.soinside.com 2019 - 2024. All rights reserved.