基于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
相关产品推荐
相关产品推荐

