我正在尝试使用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)
此代码适用于大多数图像,但对于其中一些图像,它会抛出错误 -
我在打印面数的行中出错。任何帮助,将不胜感激。
问题的原因是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有许多数据类型,即序列或集合,例如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)
从您的错误中了解到您正在尝试阅读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)
找到面数
要获得面数,它应该是:
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模式下加载。
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()