This Python code implements face recognition using Principal Component Analysis (PCA) with OpenCV. It demonstrates the common error 'IndexError: tuple index out of range' and provides a solution for handling it. Here's a breakdown of the code, the error, and how to fix it.

import cv2
import os
import numpy as np
from sklearn.decomposition import PCA

def detect_face(img, face_cascade):
    gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
    faces = face_cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=5, minSize=(30, 30), flags=cv2.CASCADE_SCALE_IMAGE)
    if (len(faces) == 0):
        return None
    for (x, y, w, h) in faces:
        face = gray[y:y + w, x:x + h].astype(np.float32)
        face = cv2.resize(face, (150,150))
        return face


def prepare_training_data(data_folder_path):
    face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_alt.xml')
    dirs = os.listdir(data_folder_path)
    faces = []
    labels = []
    for dir_name in dirs:
        label = int(dir_name)
        subject_dir_path = data_folder_path + '/' + dir_name
        subject_images_names = os.listdir(subject_dir_path)

        for image_name in subject_images_names:
            image_path = subject_dir_path + '/' + image_name
            image = cv2.imread(image_path)

            if image is None:
                continue

            gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
            rect = face_cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=5, minSize=(30, 30),flags=cv2.CASCADE_SCALE_IMAGE)
            for (x, y, w, h) in rect:
                face = gray[y:y + w, x:x + h].astype(np.float32)
                face = cv2.resize(face, (150, 150))
                if face is not None:
                   face_vector = np.reshape(face,(1,-1))[0]
                   faces.append(face_vector)
                   labels.append(label)

    faces= np.array(faces)
    labels= np.array(labels)

    return faces, labels

def preprocess_image(img, face_cascade, pca):
    face = detect_face(img, face_cascade)
    if face is not None:
        face_pca = pca.transform(face.reshape(1, -1))
        img_processed = cv2.cvtColor(face, cv2.COLOR_GRAY2RGB)
        return face_pca, img_processed
    else:
        return None, None

def main():
    cap = cv2.VideoCapture(0)
    stop = False
    face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
    pca = PCA(n_components=60, svd_solver='full')
    faces, labels = prepare_training_data('raw1')
    faces = pca.fit_transform(faces)

    while not stop:
        success, img = cap.read()
        face_pca, img_processed = preprocess_image(img, face_cascade, pca)
        if face_pca is not None:
            subjects = ['xu', 'LU', 'ZHOU']
            img1 = img_processed.copy()
            faces = face_cascade.detectMultiScale(img, scaleFactor=1.1, minNeighbors=5, minSize=(30, 30),flags=cv2.CASCADE_SCALE_IMAGE)
            if len(faces) > 0:
                (x, y, w, h) = faces[0]
                cv2.rectangle(img1, (x, y), (x + w, y + h), (0, 255, 0), 2)
                min_d = 1000000000000
                c = -1
                for i, f in enumerate(faces):
                    d = ((face_pca - f) ** 2).sum()
                    if d < min_d:
                        min_d = d
                        c = labels[i]
                print(subjects[c])
                cv2.putText(img1, subjects[c], (x, y), cv2.FONT_HERSHEY_COMPLEX, 1, (128, 128, 0), 2)
                cv2.imshow('test', img1)
                cv2.imshow('img', img1)
                c = cv2.waitKey(1)
                if c & 0xFF == ord('q'):
                    stop = True
                    cv2.destroyAllWindows()

if __name__ == '__main__':
    main()

The Error: 'IndexError: tuple index out of range'

This error occurs when you try to access an element in a tuple using an index that is outside the bounds of the tuple's length. In this code, the error occurs in the main() function:

(x, y, w, h) = faces[0]

The face_cascade.detectMultiScale() function returns a tuple of rectangles representing detected faces. If no faces are found, the tuple will be empty. Attempting to access the first element (faces[0]) of an empty tuple causes the IndexError.

Error Handling

To fix the error, you need to check if the faces tuple is empty before accessing its elements. The corrected code snippet looks like this:

faces = face_cascade.detectMultiScale(img, scaleFactor=1.1, minNeighbors=5, minSize=(30, 30),flags=cv2.CASCADE_SCALE_IMAGE)
            if len(faces) > 0:
                (x, y, w, h) = faces[0]
                # Rest of the code for drawing rectangle and processing the face
            else:
                # Code for handling the case when no face is detected

This code checks if len(faces) is greater than zero. If it is, then it proceeds to extract the coordinates of the first detected face. Otherwise, you can implement a different behavior, such as displaying a message indicating that no face was detected.

Additional Optimization

  1. Reduce Unnecessary Calculations: You can improve efficiency by moving the calculation of faces outside the while loop. Since the face detection parameters don't change, you can calculate faces only once before the loop starts.

  2. Early Exit from Loops: If a face is detected, the for loop iterating over faces can be exited early. This can save unnecessary processing time.

Complete Optimized Code:

import cv2
import os
import numpy as np
from sklearn.decomposition import PCA

# ... (Previous functions remain the same)

def main():
    cap = cv2.VideoCapture(0)
    stop = False
    face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
    pca = PCA(n_components=60, svd_solver='full')
    faces, labels = prepare_training_data('raw1')
    faces = pca.fit_transform(faces)

    while not stop:
        success, img = cap.read()
        face_pca, img_processed = preprocess_image(img, face_cascade, pca)
        if face_pca is not None:
            subjects = ['xu', 'LU', 'ZHOU']
            img1 = img_processed.copy()
            faces = face_cascade.detectMultiScale(img, scaleFactor=1.1, minNeighbors=5, minSize=(30, 30),flags=cv2.CASCADE_SCALE_IMAGE)
            if len(faces) > 0:
                (x, y, w, h) = faces[0]
                cv2.rectangle(img1, (x, y), (x + w, y + h), (0, 255, 0), 2)
                min_d = 1000000000000
                c = -1
                for i, f in enumerate(faces):
                    d = ((face_pca - f) ** 2).sum()
                    if d < min_d:
                        min_d = d
                        c = labels[i]
                        break # Exit loop if a match is found
                print(subjects[c])
                cv2.putText(img1, subjects[c], (x, y), cv2.FONT_HERSHEY_COMPLEX, 1, (128, 128, 0), 2)
                cv2.imshow('test', img1)
                cv2.imshow('img', img1)
                c = cv2.waitKey(1)
                if c & 0xFF == ord('q'):
                    stop = True
                    cv2.destroyAllWindows()

if __name__ == '__main__':
    main()

By handling the IndexError and implementing these optimization techniques, you've made your face recognition code more robust and efficient.

Python Face Recognition with PCA: Error Handling and Optimization

原文地址: https://www.cveoy.top/t/topic/mJPG 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录