Python OpenCV 人脸检测代码有时会引发 `'tuple' object has no attribute 'shape'`
Python OpenCV face detection code sometimes raises `'tuple' object has no attribute 'shape'`
我正在尝试使用 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' object has no attribute 'shape'
我在打印面数的行中出错。任何帮助将不胜感激。
从您的错误了解到您正在尝试阅读 shape
。但是shape是numpy.ndarray
的属性。您正在尝试从面部检测结果中读取形状。但是那只会return的位置而已。看种类。这里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
like len(faces)
来查找面数
获取面数应该是:
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 模式下加载。
问题的原因是detectMultiScale
return在没有匹配时是一个空元组()
,但是在有匹配时是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,这表明 return 值应该是 "objects"。
OpenCV 有很多这样的缺点,神秘的错误消息也无济于事。处理它的一种方法是将日志记录语句或断言添加到您的代码中,以检查所有内容是否都是您期望的类型。
探索库如何在 repl 中工作也非常有用,例如 ipython。这用于 .
在这种情况下,您可以通过不使用 shape
来解决您的问题。 Python 有许多数据类型是序列或集合,例如 tuple
、list
和 dict
。所有这些都实现了 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)
我正在尝试使用 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' object has no attribute 'shape'
我在打印面数的行中出错。任何帮助将不胜感激。
从您的错误了解到您正在尝试阅读 shape
。但是shape是numpy.ndarray
的属性。您正在尝试从面部检测结果中读取形状。但是那只会return的位置而已。看种类。这里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
like len(faces)
获取面数应该是:
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 模式下加载。
问题的原因是detectMultiScale
return在没有匹配时是一个空元组()
,但是在有匹配时是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,这表明 return 值应该是 "objects"。
OpenCV 有很多这样的缺点,神秘的错误消息也无济于事。处理它的一种方法是将日志记录语句或断言添加到您的代码中,以检查所有内容是否都是您期望的类型。
探索库如何在 repl 中工作也非常有用,例如 ipython。这用于
在这种情况下,您可以通过不使用 shape
来解决您的问题。 Python 有许多数据类型是序列或集合,例如 tuple
、list
和 dict
。所有这些都实现了 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)