对surprise一些解释 以及用法.md

文章目录

0. 参考

文章来源
其他用法
其他用法2
记录使用时候遇到的坑
surprise原始库

1. 1解释一下什么是raw_id和inner_id?

    i. 用户和项目有自己的raw_id和inner_id,原生id是评分文件或者pandas数据集中定义的id,重点在于要知道你使用predict()或者其他方法时候接收原生的id
    ii. 在训练集创建时,每一个原生的id映射到inner id(这是一个唯一的整数,方便surprise操作),原生id和内部id之间的转换可以用训练集中的to_inner_uid(), to_inner_iid(), to_raw_uid(), 以及to_raw_iid()方法

1.2 默认数据集下载到了哪里?怎么修改这个位置

    i. 默认数据集下载到了——“~/.surprise_data”中
    ii. 如果需要修改,可以通过设置“SURPRISE_DATA_FOLDER”环境变量来修改位置

2API合集

2.1推荐算法包

    random_pred.NormalPredictor Algorithm predicting a random rating based on the distribution of the training set, which is assumed to be normal.
    baseline_only. BaselineOnly Algorithm predicting the baseline estimate for given user and item.
    knns.KNNBasic A basic collaborative filtering algorithm.
    knns.KNNWithMeans A basic collaborative filtering algorithm, taking into account the mean ratings of each user.
    knns.KNNWithZScore A basic collaborative filtering algorithm, taking into account the z-score normalization of each user.
    knns.KNNBaseline A basic collaborative filtering algorithm taking into account a baseline rating.
    matrix_factorization.SVD The famous SVD algorithm, as popularized by Simon Funk during the Netflix Prize.
    matrix_factorization.SVDpp The SVD++ algorithm, an extension of SVD taking into account implicit ratings.
    matrix_factorization.NMF A collaborative filtering algorithm based on Non-negative Matrix Factorization.
    slope_one.SlopeOne A simple yet accurate collaborative filtering algorithm.
    co_clustering.CoClustering A collaborative filtering algorithm based on co-clustering.

2.2 推荐算法基类

2.2.1 class surprise.prediction_algorithms.algo_base.AlgoBase(**kwargs)

2.2.2如果算法需要计算相似度,那么baseline_options参数可以用来配置

2.2.3方法介绍:

2.2.3.1compute_baselines() 计算用户和项目的基线,这个方法只能适用于Pearson相似度或者BaselineOnly算法,返回一个包含用户相似度和用户相似度的元组
2.2.3.2 compute_similarities() 相似度矩阵,计算相似度矩阵的方式取决于sim_options算法创建时候所传递的参数,返回相似度矩阵
2.2.3.3default_preditction() 默认的预测值,如果计算期间发生了异常,那么预测值则使用这个值。默认情况下时所有评分的均值(可以在子类中重写,以改变这个值),返回一个浮点类型
2.2.3.4fit(trainset) 在给定的训练集上训练算法,每个派生类都会调用这个方法作为训练算法的第一个基本步骤,它负责初始化一些内部结构和设置self.trainset属性,返回self指针
2.2.3.5 get_neighbors(iid, k) 返回inner id所对应的k个最近邻居的,取决于这个iid所对应的是用户还是项目(由sim_options里面的user_based是True还是False决定),返回K个最近邻居的内部id列表
2.2.3.6 predict(uid, iid, r_ui=None, clip=True, verbose=False) 计算给定的用户和项目的评分预测,该方法将原生id转换为内部id,然后调用estimate每个派生类中定义的方法。如果结果是一个不可能的预测结果,那么会根据default_prediction()来计算预测值
            另外解释一下clip,这个参数决定是否对预测结果进行近似。举个例子来说,如果预测结果是5.5,而评分的区间是[1,5],那么将预测结果修改为5;如果预测结果小于1,那么修改为1。默认为True
            verbose参数决定了是否打印每个预测的详细信息。默认值为False
            返回值,一个rediction对象,包含了:
                a) 原生用户id
                b) 原生项目id
                c) 真实评分
                d) 预测评分
                e) 可能对后面预测有用的一些其他的详细信息
2.2.3.7 test(testset, verbose=False) 在给定的测试集上测试算法,即估计给定测试集中的所有评分。返回值是prediction对象的列表
2.2.3.8

2.3 预测模块

2.3.1 surprise.prediction_algorithms.predictions模块定义了Prediction命名元组和PredictionImpossible异常

2.3.2Prediction

2.3.2.1用于储存预测结果的命名元组
2.3.2.2仅用于文档和打印等目的
2.3.2.3 参数:
            uid 原生用户id
            iid 原生项目id
            r_ui 浮点型的真实评分
            est 浮点型的预测评分
            details 预测相关的其他详细信息

2.3.3 surprise.prediction_algorithms.predictions.PredictionImpossible

2.3.3.1当预测不可能时候,出现这个异常
2.3.3.2 这个异常会设置当前的预测评分变为默认值(全局平均值)

2.4 model_selection包

2.4.1 交叉验证迭代器

2.4.1.1 该模块中包含各种交叉验证迭代器:
            KFold 基础交叉验证迭代器
            RepeatedKFold 重复KFold交叉验证迭代器
            ShuffleSplit 具有随机训练集和测试集的基本交叉验证迭代器
            LeaveOneOut 交叉验证迭代器,其中每个用户再测试集中只有一个评级
            PredefinedKFold 使用load_from_folds方法加载数据集时的交叉验证迭代器
2.4.1.2 该模块中还包含了将数据集分为训练集和测试集的功能
            train_test_split(data, test_size=0,2, train_size=None, random_state=None, shuffle=True)
                 data,要拆分的数据集
                 test_size,如果是浮点数,表示要包含在测试集中的评分比例;如果是整数,则表示测试集中固定的评分数;如果是None,则设置为训练集大小的补码;默认为0.2
                 train_size,如果是浮点数,表示要包含在训练集中的评分比例;如果是整数,则表示训练集中固定的评分数;如果是None,则设置为训练集大小的补码;默认为None
                 random_state,整形,一个随机种子,如果多次拆分后获得的训练集和测试集没有多大分别,可以用这个参数来定义随机种子
                 shuffle,布尔值,是否在数据集中改变评分,默认为True

2.4.2 交叉验证

        surprise.model_selection.validation.cross_validate(algo, data, measures=[u'rmse',u'mae'], cv=None, return_train_measures=False, n_jobs=1, pre_dispatch=u'2 * n_jobs', verbose=False)
            ® algo,算法
            ® data,数据集
            ® measures,字符串列表,指定评估方案
            ® cv,交叉迭代器或者整形或者None,如果是迭代器那么按照指定的参数;如果是int,则使用KFold交叉验证迭代器,以参数为折叠次数;如果是None,那么使用默认的KFold,默认折叠次数5
            ® return_train_measures,是否计算训练集的性能指标,默认为False
            ® n_jobs,整形,并行进行评估的最大折叠数。如果为-1,那么使用所有的CPU;如果为1,那么没有并行计算(有利于调试);如果小于-1,那么使用(CPU数目 + n_jobs + 1)个CPU计算;默认值为1
            ® pre_dispatch,整形或者字符串,控制在并行执行期间调度的作业数。(减少这个数量可有助于避免在分配过多的作业多于CPU可处理内容时候的内存消耗)这个参数可以是:
                 None,所有作业会立即创建并生成
                 int,给出生成的总作业数确切数量
                 string,给出一个表达式作为函数n_jobs,例如“2*n_jobs”
            默认为2*n_jobs
        返回值是一个字典:
            ® test_*,*对应评估方案,例如“test_rmse”
            ® train_*,*对应评估方案,例如“train_rmse”。当return_train_measures为True时候生效
            ® fit_time,数组,每个分割出来的训练数据评估时间,以秒为单位
            ® test_time,数组,每个分割出来的测试数据评估时间,以秒为单位

2.4.3 参数搜索

2.4.3.1 class surprise.model_selection.search.GridSearchCV(algo_class, param_grid, measures=[u’rmse’, u’mae’], cv=None, refit=False, return_train_measures=False, n_jobs=1, pre_dispatch=u’2 * n_jobs’, joblib_verbose=0)
            ® 参数类似于上文中交叉验证
            ® refit,布尔或者整形。如果为True,使用第一个评估方案中最佳平均性能的参数,在整个数据集上重新构造算法measures;通过传递字符串可以指定其他的评估方案;默认为False
            ® joblib_verbose,控制joblib的详细程度,整形数字越高,消息越多
2.4.3.2 内部方法:
            a) best_estimator,字典,使用measures方案的最佳评估值,对所有的分片计算平均
            b) best_score,浮点数,计算平均得分
            c) best_params,字典,获得measure中最佳的参数组合
            d) best_index,整数,获取用于该指标cv_results的最高精度(平均下来的)的指数
            e) cv_results,数组字典,measures中所有的参数组合的训练和测试的时间
            f) fit,通过cv参数给出不同的分割方案,对所有的参数组合计算
            g) predit,当refit为False时候生效,传入数组,见上文
            h) test,当refit为False时候生效,传入数组,见上文
2.4.3.3 class surprise.model_selection.search.RandomizedSearchCV(algo_class,param_distributions,n_iter = 10,measures = [u’rmse’,u’mae’],cv = None,refit = False,return_train_measures = False,n_jobs = 1,pre_dispatch = u’2 * n_jobs’,random_state =无,joblib_verbose = 0 )
        随机抽样进行计算而非像上面的进行琼剧

2.5 相似度模块

2.5.1 similarities模块中包含了用于计算用户或者项目之间相似度的工具:

1) cosine
2) msd
3) pearson
4) pearson_baseline

2.6 精度模块

2.6.1surprise.accuracy模块提供了用于计算一组预测的精度指标的工具:

2.6.1.1) rmse(均方根误差)
2.6.1.2) mae(平均绝对误差)
2.6.1.3) fcp

2.7 数据集模块

2.7.1dataset模块定义了用于管理数据集的Dataset类和其他子类

2.7.2 class surprise.dataset.Dataset(reader)

2.7.3内部方法:

2.7.3.1) load_builtin(name=u’ml-100k’),加载内置数据集,返回一个Dataset对象
2.7.3. 2) load_from_df(df, reader),df(dataframe),数据框架,要求必须具有三列(要求顺序),用户原生id,项目原生id,评分;reader,指定字段内容
2.7.3. 3) load_from_file(file_path, reader),从文件中加载数据,参数为路径和读取器
2.7.3.4) load_from_folds(folds_files, reader),处理一种特殊情况,movielens-100k数据集中已经定义好了训练集和测试集,可以通过这个方法导入

2.8 训练集类

2.8.1class surprise.Trainset(ur, ir, n_users, n_items, n_ratings, rating_scale, offset, raw2inner_id_users, raw2inner_id_items)

2.8.2属性分析:

2.8.2.1) ur,用户评分列表(item_inner_id,rating)的字典,键是用户的inner_id
2.8.2. 2) ir,项目评分列表(user_inner_id,rating)的字典,键是项目的inner_id
2.8.2.3) n_users,用户数量
2.8.2.4) n_items,项目数量
2.8.2.5) n_ratings,总评分数
2.8.2.6) rating_scale,评分的最高以及最低的元组
2.8.2. 7) global_mean,所有评级的平均值

2.8.3 方法分析:

2.8.3.1) all_items(),生成函数,迭代所有项目,返回所有项目的内部id
2.8.3.2) all_ratings(),生成函数,迭代所有评分,返回一个(uid, iid, rating)的元组
2.8.3. 3) all_users(),生成函数,迭代所有的用户,然会用户的内部id
2.8.3. 4) build_anti_testset(fill=None),返回可以在test()方法中用作测试集的评分列表,参数决定填充未知评级的值,如果使用None则使用global_mean
2.8.3.5) knows_item(iid),标志物品是否属于训练集
2.8.3. 6) knows_user(uid),标志用户是否属于训练集
2.8.3. 7) to_inner_iid(riid),将项目原始id转换为内部id
2.8.3.8) to_innser_uid(ruid),将用户原始id转换为内部id
2.8.3. 9) to_raw_iid(iiid),将项目的内部id转换为原始id
2.8.3.10) to_raw_uid(iuid),将用户的内部id转换为原始id

2.9读取器类

2.9.1class surprise.reader.Reader(name=None, line_format=u’user item rating’, sep=None, rating_scale=(1, 5), skip_lines=0)

    Reader类用于解析包含评分的文件,要求这样的文件每行只指定一个评分,并且需要每行遵守这个接口:用户;项目;评分;[时间戳],不要求顺序,但是需要指定

2.9.2参数分析:

2.9.2.1) name,如果指定,则返回一个内置的数据集Reader,并忽略其他参数,可接受的值是"ml-100k",“m1l-1m”和“jester”。默认为None
2.9.2.2) line_format,string类型,字段名称,指定时需要用空格分割,默认是“user item rating”
2.9.2. 3) sep,char类型,指定字段之间的分隔符
2.9.2.4) rating_scale,元组类型,评分区间,默认为(1,5)
2.9.2.5) skip_lines,int类型,要在文件开头跳过的行数,默认为0

2.10 转储模块

2.10.1surprise.dump.dump(file_name, predictions=None, algo=None, verbose=0)

2.10.1.1一个pickle的基本包装器,用来序列化预测或者算法的列表
2.10.1.2参数分析:
            a) file_name,str,指定转储的位置
            b) predictions,Prediction列表,用来转储的预测
            c) algo,Algorithm,用来转储的算法
            d) verbose,详细程度,0或者1

2.10.2 surprise.dump.load(file_name)

2.10.2.1用于读取转储文件
2.10.2.2返回一个元组(predictions, algo),其中可能为None
import requests import time import hashlib import base64 import cv2 import numpy as np import matplotlib.pyplot as plt import threading import json import os import random from datetime import datetime from collections import deque class FaceExpressionAnalyzer: def __init__(self, appid="", api_key="", url="http://tupapi.xfyun.cn/v1/expression", simulation_mode=False): """初始化表情分析器,设置API认证信息和URL""" self.appid = appid self.api_key = api_key self.url = url self.emotion_history = [] self.timestamps = [] self.running = False self.simulation_mode = simulation_mode # 模拟模式开关 self.emotion_smoother = deque(maxlen=5) # 用于平滑情绪输出 # 中英文情绪映射 self.emotion_map = { 'angry': '生气', 'disgust': '厌恶', 'fear': '害怕', 'happy': '开心', 'sad': '悲伤', 'surprise': '惊讶', 'neutral': '中性' } print(f"表情分析器初始化完成,{'模拟模式已启用' if simulation_mode else 'API模式已启用'}") def get_header(self, image_name, image_url=None, image_data=None): """生成API请求头,包含认证信息""" cur_time = str(int(time.time())) # 根据图片数据类型构建不同的请求参数 if image_data is not None: param = json.dumps({"image_name": image_name, "image_url": "", "image_data": image_data}) else: param = json.dumps({"image_name": image_name, "image_url": image_url}) param_base64 = base64.b64encode(param.encode('utf-8')).decode('utf-8') checksum = hashlib.md5((self.api_key + cur_time + param_base64).encode('utf-8')).hexdigest() header = { 'X-CurTime': cur_time, 'X-Param': param_base64, 'X-Appid': self.appid, 'X-CheckSum': checksum, 'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8' } return header def simulate_api_response(self, face_count=1): """模拟API响应,支持多人脸识别""" time.sleep(0.5) # 模拟网络延迟 faces = [] for i in range(face_count): expression = random.choice(list(self.emotion_map.keys())) faces.append({ "expression": expression, "face_rectangle": { "top": random.randint(50, 300), "left": random.randint(50 + i*150, 200 + i*150), "width": random.randint(100, 200), "height": random.randint(100, 200) } }) return { "code": 0, "desc": "success", "sid": "simulated_sid", "data": { "faces": faces, "face_num": face_count } } def analyze_image_url(self, image_name, image_url): """分析网络图片中的人脸表情""" if self.simulation_mode: return self.simulate_api_response(random.randint(1, 3)) try: header = self.get_header(image_name, image_url) response = requests.post(self.url, headers=header, timeout=10) return self._parse_response(response) except Exception as e: return {"code": -4, "desc": f"请求异常: {str(e)}"} def analyze_local_image(self, image_name, image_path): """分析本地图片中的人脸表情""" if self.simulation_mode: return self.simulate_api_response(random.randint(1, 3)) try: # 读取图片并转为base64编码 if not os.path.exists(image_path): return {"code": -5, "desc": f"文件不存在: {image_path}"} img = cv2.imread(image_path) if img is None: return {"code": -6, "desc": "无法读取图片文件"} # 压缩图片直到大小合适 quality = 90 while True: _, buffer = cv2.imencode('.jpg', img, [cv2.IMWRITE_JPEG_QUALITY, quality]) image_data = buffer.tobytes() if len(image_data) <= 800 * 1024 or quality <= 10: break quality -= 10 image_base64 = base64.b64encode(image_data).decode('utf-8') header = self.get_header(image_name, image_url="", image_data=image_base64) response = requests.post(self.url, headers=header, timeout=10) return self._parse_response(response) except Exception as e: return {"code": -7, "desc": f"图片处理错误: {str(e)}"} def _parse_response(self, response): """安全解析API响应""" try: response.raise_for_status() data = response.json() # 统一API响应格式 if 'data' in data and 'expression' in data['data']: # 处理单脸响应格式 data['data'] = { "face_num": 1, "faces": [{ "expression": data['data']['expression'], "face_rectangle": data['data']['face_rectangle'] }] } return data except requests.exceptions.JSONDecodeError: return {"code": -1, "desc": "JSON解析错误", "raw_response": response.text[:200]} except requests.exceptions.HTTPError as e: return {"code": -2, "desc": f"HTTP错误: {str(e)}", "status_code": response.status_code} except Exception as e: return {"code": -3, "desc": f"请求异常: {str(e)}"} def translate_emotion(self, emotion_en): """将英文情绪翻译为中文""" return self.emotion_map.get(emotion_en, emotion_en) def capture_and_analyze(self): """从摄像头捕获图像并分析表情,支持多人脸""" cap = cv2.VideoCapture(0) if not cap.isOpened(): print("无法打开摄像头") return None, None, None # 尝试多次捕获 for _ in range(3): ret, frame = cap.read() if ret: break time.sleep(0.1) cap.release() if not ret: print("无法捕获图像") return None, None, None # 保存临时图像 timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") image_name = f"face_{timestamp}.jpg" image_path = f"temp_{timestamp}.jpg" cv2.imwrite(image_path, frame) # 分析图像 result = self.analyze_local_image(image_name, image_path) # 删除临时文件 try: os.remove(image_path) except: pass return result, frame, image_name def start_tracking(self, interval=3): """开始定时拍照并分析表情,支持多人脸""" if self.running: print("追踪已在运行中") return self.running = True self.emotion_history = [] self.timestamps = [] print(f"开始表情追踪,每{interval}秒拍摄一次...") def track_loop(): while self.running: result, frame, image_name = self.capture_and_analyze() timestamp = datetime.now().strftime("%H:%M:%S") if result and 'code' in result and result['code'] == 0: if 'data' in result and 'face_num' in result['data']: face_num = result['data']['face_num'] print(f"检测到 {face_num} 张人脸") # 处理每张人脸 expressions = [] for face in result['data']['faces']: expression_en = face['expression'] expression_cn = self.translate_emotion(expression_en) expressions.append(expression_cn) # 绘制人脸框和表情 rect = face['face_rectangle'] if isinstance(rect, list): rect = rect[0] # 处理单脸格式 top = rect['top'] left = rect['left'] width = rect['width'] height = rect['height'] # 在图像上绘制结果 cv2.rectangle(frame, (left, top), (left+width, top+height), (0, 255, 0), 2) cv2.putText(frame, expression_cn, (left, top-10), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 255, 0), 2) # 平滑处理主要表情 if expressions: self.emotion_smoother.append(expressions[0]) smoothed_expression = max(set(self.emotion_smoother), key=list(self.emotion_smoother).count) self.emotion_history.append(smoothed_expression) self.timestamps.append(timestamp) print(f"时间: {timestamp}, 主要表情: {smoothed_expression}") if frame is not None: cv2.imshow('多人脸表情分析', frame) cv2.waitKey(1) else: print(f"分析成功但未检测到人脸: {result}") elif result: print(f"分析失败: {result.get('desc', '未知错误')}") else: print("未获取到分析结果") # 等待指定间隔,但允许提前退出 start_time = time.time() while self.running and (time.time() - start_time) < interval: time.sleep(0.1) self.tracking_thread = threading.Thread(target=track_loop) self.tracking_thread.daemon = True self.tracking_thread.start() def stop_tracking(self): """停止表情追踪""" if not self.running: print("追踪未运行") return self.running = False if hasattr(self, 'tracking_thread') and self.tracking_thread.is_alive(): self.tracking_thread.join(timeout=2.0) cv2.destroyAllWindows() print("已停止表情追踪") def plot_emotion_history(self): """绘制情感变化历史图表""" if not self.emotion_history: print("没有情感历史数据") return # 中文情绪列表 emotions_cn = list(self.emotion_map.values()) emotion_to_index = {emotion: idx for idx, emotion in enumerate(emotions_cn)} # 为每个情绪分配颜色 colors = ['red', 'green', 'purple', 'yellow', 'blue', 'orange', 'gray'] emotion_colors = {emotion: color for emotion, color in zip(emotions_cn, colors)} plt.figure(figsize=(12, 6)) # 饼图:表情分布 plt.subplot(1, 2, 1) emotion_counts = {emotion: 0 for emotion in emotions_cn} for emotion in self.emotion_history: if emotion in emotion_counts: emotion_counts[emotion] += 1 # 过滤掉计数为0的表情 filtered_emotions = [e for e in emotions_cn if emotion_counts[e] > 0] filtered_counts = [emotion_counts[e] for e in filtered_emotions] filtered_colors = [emotion_colors[e] for e in filtered_emotions] plt.pie(filtered_counts, labels=filtered_emotions, colors=filtered_colors, autopct='%1.1f%%') plt.title('表情分布') # 折线图:情感变化时间线 plt.subplot(1, 2, 2) emotion_indices = [emotion_to_index[e] for e in self.emotion_history] plt.plot(self.timestamps, emotion_indices, 'o-') # 设置Y轴为表情标签 plt.yticks(range(len(emotions_cn)), emotions_cn) plt.title('情感变化时间线') plt.xlabel('时间') plt.ylabel('表情') plt.xticks(rotation=45) plt.tight_layout() plt.show() # 主函数 def main(): print("="*40) print("多人脸表情分析系统") print("="*40) # 配置选项 print("\n请选择运行模式:") print("1. 模拟模式 (无需API密钥)") print("2. API模式 (需要有效API密钥)") mode_choice = input("请输入选择 (1/2): ").strip() simulation_mode = mode_choice == "1" if simulation_mode: analyzer = FaceExpressionAnalyzer(simulation_mode=True) else: APPID = input("请输入APPID: ").strip() API_KEY = input("请输入API_KEY: ").strip() if not APPID or not API_KEY: print("警告: APPID或API_KEY为空,将切换到模拟模式") analyzer = FaceExpressionAnalyzer(simulation_mode=True) else: analyzer = FaceExpressionAnalyzer(APPID, API_KEY) while True: print("\n===== 主菜单 =====") print("1. 分析网络图片") print("2. 分析本地图片") print("3. 拍照分析") print("4. 开始定时分析") print("5. 停止定时分析") print("6. 查看情感历史图表") print("0. 退出") choice = input("请选择功能: ").strip() if choice == "1": image_name = input("输入图片名称 (默认: test.jpg): ") or "test.jpg" image_url = input("输入图片URL: ") if image_url: result = analyzer.analyze_image_url(image_name, image_url) print("\n分析结果:") self._display_results(result) else: print("错误: URL不能为空") elif choice == "2": image_name = input("输入图片名称 (默认: test.jpg): ") or "test.jpg" image_path = input("输入图片路径: ") if image_path: result = analyzer.analyze_local_image(image_name, image_path) print("\n分析结果:") self._display_results(result) else: print("错误: 图片路径不能为空") elif choice == "3": print("请面对摄像头准备拍照...") result, frame, image_name = analyzer.capture_and_analyze() if result: print("\n分析结果:") self._display_results(result) if frame is not None: # 在图像上绘制结果 if 'code' in result and result['code'] == 0 and 'data' in result: for face in result['data']['faces']: expr_en = face['expression'] expr_cn = analyzer.translate_emotion(expr_en) # 绘制人脸框 rect = face['face_rectangle'] if isinstance(rect, list): rect = rect[0] # 处理单脸格式 top = rect['top'] left = rect['left'] width = rect['width'] height = rect['height'] cv2.rectangle(frame, (left, top), (left+width, top+height), (0, 255, 0), 2) cv2.putText(frame, f"表情: {expr_cn}", (left, top-10), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 255, 0), 2) cv2.imshow('多人脸表情分析', frame) cv2.waitKey(0) cv2.destroyAllWindows() elif choice == "4": interval = input("输入采集间隔(秒,默认3秒): ").strip() try: interval = int(interval) if interval else 3 analyzer.start_tracking(interval) except ValueError: print("无效的间隔时间,使用默认值3秒") analyzer.start_tracking() elif choice == "5": analyzer.stop_tracking() elif choice == "6": analyzer.plot_emotion_history() elif choice == "0": if analyzer.running: analyzer.stop_tracking() print("程序已退出") break else: print("无效选择,请输入0-6之间的数字") def _display_results(self, result): """显示分析结果(中文)""" if not result: print("无有效结果") return if 'code' in result and result['code'] == 0: if 'data' in result and 'face_num' in result['data']: face_num = result['data']['face_num'] print(f"检测到 {face_num} 张人脸:") for i, face in enumerate(result['data']['faces'], 1): expr_en = face['expression'] expr_cn = self.translate_emotion(expr_en) print(f"人脸 {i}: {expr_cn}") else: print("分析成功但未检测到人脸") else: error_desc = result.get('desc', '未知错误') print(f"分析失败: {error_desc}") if __name__ == "__main__": main() 讲解一下这个代码
06-20
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值