You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于SVM的面部表情检测Python代码报错:xlist未赋值即引用

解决SVM实时面部表情检测代码的xlist未定义错误

问题说明

运行基于SVM的实时面部表情检测Python代码时触发错误:

local variable 'xlist' referenced before assignment

错误根源在于get_landmark_positions函数中,当未检测到人脸时,函数内的for循环不会执行,导致xlist、ylist、hog、sum这几个变量从未被定义,直接执行return语句就会触发变量未定义的报错。

错误堆栈追踪

Message=local variable 'xlist' referenced before assignment
Source=D:\study folder\msc project SVM\Emotion-Recognition-From-Facial-Expressions-master\live.py
StackTrace:
File "D:\study folder\msc project SVM\Emotion-Recognition-From-Facial-Expressions-master\live.py", line 74, in get_landmark_positions
    return xlist, ylist, hog,sum
File "D:\study folder\msc project SVM\Emotion-Recognition-From-Facial-Expressions-master\live.py", line 78, in get_features
    xlist, ylist, hog, sum = get_landmark_positions(clahe_image)
File "D:\study folder\msc project SVM\Emotion-Recognition-From-Facial-Expressions-master\live.py", line 109, in <module> (Current frame)
    feat = get_features(crop_img)

修复方案

1. 提前初始化返回变量

在get_landmark_positions函数开头就初始化所有要返回的变量,确保无论是否检测到人脸,变量都处于已定义状态;同时修改sum变量名为sum_val,避免和Python内置函数sum冲突,还增加了防止除以0的判断:

def get_landmark_positions(img):
    # 初始化返回变量,避免未检测到人脸时变量未定义
    xlist = []
    ylist = []
    hog = np.array([])
    sum_val = 0  # 避免和内置函数sum重名
    detections = detector(img, 1)
    for k, d in enumerate(detections):  # 遍历所有检测到的人脸
        shape = predictor(img, d)  # 提取面部关键点
        shape2 = face_utils.shape_to_np(shape)
        ch = cv2.convexHull(shape2[48:68])
        M = cv2.moments(shape2[48:68])
        # 增加判断,避免M["m00"]为0时触发除以0错误
        if M["m00"] == 0:
            continue
        cX = int(M["m10"] / M["m00"])
        cY = int(M["m01"] / M["m00"])
        sum_val = 0
        for p in ch:
            i, j = p[0]
            if ((i - cX) != 0):
                v = (j - cY) / (i - cX)
                sum_val += v

        (x, y, w, h) = cv2.boundingRect(np.array([shape2[48:68]]))
        roi = img[y:y + h, x:x + w]

        win_size = (64, 128)
        img_resized = cv2.resize(img, win_size)
        d = cv2.HOGDescriptor()
        hog = d.compute(img_resized)

        hog = hog.transpose()[0]
        hog = np.asarray(hog)

        xlist.clear()
        ylist.clear()
        for i in range(1, 68):  # 存储关键点的X、Y坐标
            xlist.append(float(shape.part(i).x))
            ylist.append(float(shape.part(i).y))
    return xlist, ylist, hog, sum_val

2. 增加特征有效性判断

在get_features函数中增加对返回值的判断,当未检测到人脸时返回空特征;主循环中只有特征有效时才执行预测逻辑:

def get_features(img):
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)  # 转为灰度图
    clahe_image = clahe.apply(gray)
    xlist, ylist, hog, sum_val = get_landmark_positions(clahe_image)
    # 如果hog为空,说明未检测到人脸,返回空特征
    if len(hog) == 0:
        return []
    features2 = []
    features2.extend(hog)
    return features2

主循环内修改:

feat = get_features(crop_img)
# 只有特征不为空时才进行预测
if feat:
    proba = clf.predict_proba([feat])
    pred_value = clf.predict([feat])[0]
    print(proba)
    print(math.floor((proba[0][0]*1000000))/10000)

    # 所有表情文本绘制逻辑放在此处
    # ...(原有表情绘制代码)
else:
    # 未检测到人脸时显示提示文本
    cv2.putText(frame, '未检测到人脸', (30, 60),
                cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 255), 2, cv2.LINE_AA)

完整修改后代码

import math
import pickle
from xml.etree.ElementPath import prepare_predicate

import numpy as np
import cv2
import dlib

import imutils
import glob
import csv

from imutils import face_utils
from sklearn import datasets
from sklearn.multiclass import OneVsRestClassifier
from sklearn.model_selection import KFold
from sklearn.metrics import confusion_matrix,classification_report
from sklearn.metrics import roc_curve, auc
from sklearn.preprocessing import label_binarize
import matplotlib.pyplot as plt
from itertools import cycle
from scipy import interp
from sklearn.multiclass import OneVsRestClassifier, OneVsOneClassifier

from sklearn.svm import SVC
import pickle

detector = dlib.get_frontal_face_detector()
predictor = dlib.shape_predictor("D:\\study folder\\msc project SVM\\Emotion-Recognition-From-Facial-Expressions-master\\shape_predictor_68_face_landmarks.dat")
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))

def get_landmark_positions(img):
    # 初始化返回变量,避免未检测到人脸时变量未定义
    xlist = []
    ylist = []
    hog = np.array([])
    sum_val = 0  # 避免和内置函数sum重名
    detections = detector(img, 1)
    for k, d in enumerate(detections):  # 遍历所有检测到的人脸
        shape = predictor(img, d)  # 提取面部关键点
        shape2 = face_utils.shape_to_np(shape)
        ch = cv2.convexHull(shape2[48:68])
        M = cv2.moments(shape2[48:68])
        # 增加判断,避免M["m00"]为0时触发除以0错误
        if M["m00"] == 0:
            continue
        cX = int(M["m10"] / M["m00"])
        cY = int(M["m01"] / M["m00"])
        sum_val = 0
        for p in ch:
            i, j = p[0]
            if ((i - cX) != 0):
                v = (j - cY) / (i - cX)
                sum_val += v

        (x, y, w, h) = cv2.boundingRect(np.array([shape2[48:68]]))
        roi = img[y:y + h, x:x + w]

        win_size = (64, 128)
        img_resized = cv2.resize(img, win_size)
        d = cv2.HOGDescriptor()
        hog = d.compute(img_resized)

        hog = hog.transpose()[0]
        hog = np.asarray(hog)

        xlist.clear()
        ylist.clear()
        for i in range(1, 68):  # 存储关键点的X、Y坐标
            xlist.append(float(shape.part(i).x))
            ylist.append(float(shape.part(i).y))
    return xlist, ylist, hog, sum_val

def get_features(img):
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)  # 转为灰度图
    clahe_image = clahe.apply(gray)
    xlist, ylist, hog, sum_val = get_landmark_positions(clahe_image)
    # 如果hog为空,说明未检测到人脸,返回空特征
    if len(hog) == 0:
        return []
    features2 = []
    features2.extend(hog)
    return features2

cap = cv2.VideoCapture(0)
filename = 'D:\\study folder\\msc project SVM\\Emotion-Recognition-From-Facial-Expressions-master\\finalized_model.sav'

face_cascade = cv2.CascadeClassifier('D:\\study folder\\msc project SVM\\Emotion-Recognition-From-Facial-Expressions-master\\haarcascade_frontalface_default.xml')

clf = pickle.load(open(filename, 'rb'))
classes = ["HAPPY", "CONTEMPT", "ANGER", "DISGUST", "FEAR", "SADNESS", "SURPRISE", "NEUTRAL"]

while(True):
    _, frame = cap.read()

    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    faces = face_cascade.detectMultiScale(gray, 1.3, 5)
    for (x,y,w,h) in faces:
        cv2.rectangle(frame,(x,y),(x+w,y+h),(255,0,0),2)
        roi_gray = gray[y:y+h, x:x+w]
        roi_color = frame[y:y+h, x:x+w]
    crop_img = frame
    if len(faces) == 0:
        crop_img = frame
    else:
        crop_img = frame[y:y + h, x:x + w]

    win_size = (64, 128)

    feat = get_features(crop_img)
    # 只有特征不为空时才进行预测
    if feat:
        proba = clf.predict_proba([feat])
        pred_value = clf.predict([feat])[0]
        print(proba)
        print(math.floor((proba[0][0]*1000000))/10000)

        if(pred_value == 0):
            cv2.putText(frame, 'Happy: ' + str(math.floor((proba[0][0]*1000000))/10000) + '%', (30, 60),
                        cv2.FONT_HERSHEY_SIMPLEX, 0.6, (255, 0, 0), 2, cv2.LINE_AA)
        else:
            cv2.putText(frame, 'Happy: ' + str(math.floor((proba[0][0] * 1000000)) / 10000) + '%', (30, 60),
                        cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 255), 2, cv2.LINE_AA)

        if (pred_value == 2):
             cv2.putText(frame, 'ANGER: ' + str(math.floor((proba[0][1]*1000000))/10000), (30, 100),
                        cv2.FONT_HERSHEY_SIMPLEX, 0.6, (255, 0, 0), 2, cv2.LINE_AA)
        else:
            cv2.putText(frame, 'ANGER: ' + str(math.floor((proba[0][1] * 1000000)) / 10000), (30, 100),
                        cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 255), 2, cv2.LINE_AA)
        if (pred_value == 3):
            cv2.putText(frame, 'DISGUST: ' + str(math.floor((proba[0][2]*1000000))/10000), (30, 140),
                        cv2.FONT_HERSHEY_SIMPLEX, 0.6, (255, 0, 0), 2, cv2.LINE_AA)
        else:
            cv2.putText(frame, 'DISGUST: ' + str(math.floor((proba[0][2] * 1000000)) / 10000), (30, 140),
                        cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 255), 2, cv2.LINE_AA)
        if(pred_value == 4):
            cv2.putText(frame, 'FEAR: ' + str(math.floor((proba[0][3]*1000000))/10000), (30, 180),
                    cv2.FONT_HERSHEY_SIMPLEX, 0.6, (255, 0, 0), 2, cv2.LINE_AA)
        else:
            cv2.putText(frame, 'FEAR: ' + str(math.floor((proba[0][3] * 1000000)) / 10000), (30, 180),
                        cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 255), 2, cv2.LINE_AA)

        if (pred_value == 5):
            cv2.putText(frame, 'SADNESS: ' + str(math.floor((proba[0][4]*1000000))/10000), (30, 220),
                        cv2.FONT_HERSHEY_SIMPLEX, 0.6, (255, 0, 0), 2, cv2.LINE_AA)
        else:
            cv2.putText(frame, 'SADNESS: ' + str(math.floor((proba[0][4] * 1000000)) / 10000), (30, 220),
                        cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 255), 2, cv2.LINE_AA)
        if(pred_value == 6):
            cv2.putText(frame, 'SURPRISE: ' + str(math.floor((proba[0][5]*1000000))/10000), (30, 260),
                        cv2.FONT_HERSHEY_SIMPLEX, 0.6, (255, 0, 0), 2, cv2.LINE_AA)
        else:
            cv2.putText(frame, 'SURPRISE: ' + str(math.floor((proba[0][5] * 1000000)) / 10000), (30, 260),
                        cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 255), 2, cv2.LINE_AA)

        if (pred_value == 7):
            cv2.putText(frame, 'NEUTRAL: ' + str(math.floor((proba[0][6]*1000000))/10000), (30, 300),
                    cv2.FONT_HERSHEY_SIMPLEX, 0.6, (255, 0, 0), 2, cv2.LINE_AA)
        else:
            cv2.putText(frame, 'NEUTRAL: ' + str(math.floor((proba[0][6] * 1000000)) / 10000), (30, 300),
                        cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 255), 2, cv2.LINE_AA)
    else:
        # 未检测到人脸时显示提示
        cv2.putText(frame, '未检测到人脸', (30, 60),
                    cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 255), 2, cv2.LINE_AA)
         
    cv2.imshow('frame',frame)
    key = cv2.waitKey(1)

    if key == 27:
        break

cap.release()
cv2.destroyAllWindows()

内容的提问来源于stack exchange,提问作者N

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 13:15:27