В коде обнаружения лица Python OpenCV иногда возникает "объект кортежа", не имеющий атрибута "форма"
Я пытаюсь построить приложение для обнаружения лиц в Python с использованием OpenCV.
Пожалуйста, смотрите ниже мои фрагменты кода:
# 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)
Этот код отлично работает для большинства изображений, но для некоторых из них он выдает ошибку -
Я получаю ошибку в строке, где я печатаю количество лиц. Любая помощь будет оценена.
3 ответа
Причиной проблемы является то, что 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), но это не так.
Это поведение и причины этого не объяснены в документации, которая вместо этого указывает, что возвращаемое значение должно быть "объектами".
У 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)
Из вашей ошибки понимаю, что вы пытаетесь прочитать 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()