2016-06-11 31 views
0

Ich versuche, eine Gesichtserkennungs-Anwendung in Python mit opencv zu bauen.
Bitte siehe unten für meinen Code-Schnipsel:Python OpenCV Gesichtserkennung Code wirft manchmal `'Tupel' Objekt hat kein Attribut 'Shape'`

# 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) 

Dieser Code für die meisten der Bilder funktioniert gut, aber für einige von ihnen wirft er einen Fehler -

AttributeError: 'tuple' object has no attribute 'shape' enter image description here

ich Fehler in der Zeile, in Ich drucke die Anzahl der Gesichter. Jede Hilfe wäre willkommen.

+2

Stellen Sie keine Bilder und Links auf Ihre Probleme, den Code und die Probleme Post ** hier ** in Frage. –

+0

Ich habe den Code veröffentlicht ... wusste nicht, dass das Posten von Bildern und Links zu den Problemen nicht erlaubt ist. Bitte nicht die Frage ablehnen. –

+0

@Maddy Es ist nicht so, dass es nicht erlaubt ist - es ist, dass ich mich nicht bei Stack Overflow anmelde, um dann auf Links zu anderen Seiten zu gehen, um zu sehen, was dein Problem ist. Es dauert ein paar Sekunden, um den Code in Ihre Frage zu kopieren und einzufügen. Wenn Sie sich nicht darum bemüht haben, Fragen zu stellen, werden sich die Leute nicht anstrengen. –

Antwort

1

Die Ursache des Problems ist, dass detectMultiScale ein leeres Tupel gibt (), wenn es keine Übereinstimmungen gibt, aber ein numpy.ndarray wenn es Begegnungen.

>>> 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'>() 

Man könnte erwarten, dass ein negatives Ergebnis eine ndarray der Form sein würde (0,4), aber das ist nicht der Fall.

Dieses Verhalten und die Begründung dahinter ist not explained in the documentation, die stattdessen angibt, dass der Rückgabewert "Objekte" sein sollte.

OpenCV hat so viele Warzen, und die kryptischen Fehlermeldungen helfen nicht. Eine Möglichkeit, mit ihr umzugehen, besteht darin, Protokollierungsanweisungen hinzuzufügen oder in Ihrem Code zu bestätigen, um zu überprüfen, ob alles der von Ihnen erwartete Typ ist.

Es ist auch sehr nützlich zu erkunden, wie eine Bibliothek in einem repl wie ipython funktioniert. Dies wird in Rahul K P's answer verwendet. In diesem Fall können Sie Ihr Problem lösen, indem Sie shape nicht verwenden.Python hat viele Datentypen, die Sequenzen oder Sammlungen sind, zum Beispiel tuple, list und dict. Alle diese implementieren die eingebaute Funktion len() und Sie können sie auch über for x in y durchlaufen. Im Gegensatz dazu ist shape nur eine Eigenschaft von numpy.ndarray und wird in keinem der integrierten Python-Datentypen gefunden.

Ihr Code sollte funktionieren, wenn Sie es umschreiben, um len(faces) anstelle von faces.shape[0] zu verwenden, da der ehemalige mit Tuple und NDarray funktioniert.

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

Von Ihrem Fehler verstehen, dass Sie versuchen, die shape zu lesen. Aber shape ist das Attribut numpy.ndarray. Sie versuchen, die Form aus dem Ergebnis der Gesichtserkennung zu lesen. Aber das wird nur die Position nur zurückgeben. Schau dir die Typen an. Hier ist img ein Bild und faces ist das Ergebnis der Gesichtserkennung. Ich hoffe du hast das Problem.

Aktualisiert mit vollem Code. Weitere Klärung

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 

Blick auf die diffrence.

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' 

Wenn Sie die Anzahl der Gesichter möchten. Es ist in Form einer Tupelliste. Sie können die Anzahl der Flächen finden len wie len(faces)

+1

Aber warum der Code funktioniert gut für die meisten Bilder und wirft Fehler nur bei einigen Bildern. –

+0

http://docs.scipy.org/doc/numpy-1.10.1/reference/arrays.tarray.html Schauen Sie sich die Dokumentation von 'numpy.ndarry' an. –

+0

@RahulKP: Ich sehe, dass Sie opencv 2.4.9 verwenden. Ich benutze Version 3.0 und es stellt sich heraus, 'DetectMultiScale' wird entweder ein leeres' Tupel' (keine Übereinstimmungen) oder 'ndarray' (Übereinstimmungen gefunden) zurückgeben. Ist es in Version 2.4 gleich? Ich habe mehr Details in [meine Antwort] (http://stackoverflow.com/a/37761914/1977847) zur Verfügung gestellt. –

1

Verwendung Um die Anzahl der Gesichter bekommen es sein sollte:

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

Ich würde auch empfehlen, dass Bild zu konvertieren in Graustufen Sie schreiben sollen:

gray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY) statt gray = cv2.cvtColor(im, cv2.COLOR_RGB2GRAY) als Farbbilder von OpenCV in BGR Modus geladen werden.

+0

Sie haben recht mit 'BGR' vs' RGB'. Aber in diesem Fall sollte es keinen Unterschied machen, da die Graustufenumwandlung nur die drei Kanäle mittelt. –

+0

Es ist nicht korrekt zu sagen, dass 'detectMultiScale' eine Liste zurückgibt. Es gibt ein ndarray oder ein leeres Tupel zurück. –

+0

Ja, es ist falsch. Ich werde es bearbeiten. Vielen Dank. – shiva