В коде обнаружения лица 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)

Этот код отлично работает для большинства изображений, но для некоторых из них он выдает ошибку -

AttributeError: объект 'tuple' не имеет атрибута 'shape'

Я получаю ошибку в строке, где я печатаю количество лиц. Любая помощь будет оценена.

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()
Другие вопросы по тегам