社区首页
技术讨论创新帖
全部新帖
资料区
社区活动
联系管理员
★ 社区积分制度
★ 新手必读
★ 申请版主★
请
登录
后使用快捷导航
没有帐号?
注册
首页
|
电子技术
|
嵌入式
模拟电子
单片机
电源管理
传感器
半导体
电子应用
|
工业控制
物联网
汽车电子
网络通信
医疗电子
手机便携
测试测量
安防电子
家用电子
机器人
新能源
电子头条
|
社区
|
论坛
测评
博客
大学堂
|
下载
|
下载中心
电路图
精品文集
电路图
|
参考设计
|
Datasheet
|
活动
|
直播
datasheet
datasheet
文章
搜索
登录
注册
中文
En
论坛
切换旧版
电子工程世界-论坛
»
论坛
›
电子技术交流
›
嵌入式系统
›
[RV1106&InsightFace]--InsightFace实现视频中的人脸识 ...
返回列表
发新帖
回复
阅
111
|
回
0
许大锤
当前离线
一粒金砂(中级)
最后登录
2025-1-9
在线时间
7 小时
威望
42分
芯积分
77分
(兑换)
E金币
0枚
(兑换)
(兑换)
好友
0
许大锤
15
帖子
1
TA的资源
一粒金砂(中级)
+ 好友
私信
楼主
发表于2025-1-9 15:48
只看该作者
[RV1106&InsightFace]--InsightFace实现视频中的人脸识别
[复制链接]
前文已经实现了本地部署,也实现图片和视频的人脸检测。https://bbs.eeworld.com.cn/thread-1303465-1-1.html#pid3385431 接下来是实现视频中人脸识别。 ## 准备 ```shell pip install torch opencv-python insightface numpy scikit-learn pip install insightface pip install onnxruntime pip install onnxruntime-gpu pip install opencv-contrib-python ``` 为了让输出的视频包含音频,建议安装FFmpeg,具体如何安装网上有很多教程。 接下来是实现视频中人脸识别,但感觉处理速度挺慢的,所以每5帧进行一次识别,中间做的识别框就做插值处理了,还有感觉合成音频也蛮费时间的。 ## 构建人脸数据库 先准备几个人脸图片,修改image_path的路径,name变量是视频中标记的名字,建议用英文,中文可能会出问题。 ```python # 添加新的人脸 image_path = 'img/guanyu.jpg' # 已知人脸图片路径 name = "Guan Yu" # 对应的身份名称 ``` 完整代码: ```python import cv2 import insightface import pickle from insightface.app import FaceAnalysis # 初始化 ArcFace 模型 app = FaceAnalysis() app.prepare(ctx_id=0, det_size=(640, 640)) # 数据库路径 database_path = './face_database.pkl' try: with open(database_path, 'rb') as f: face_database = pickle.load(f) print("已加载人脸数据库") except FileNotFoundError: face_database = {} print("人脸数据库不存在,创建空数据库") # 添加新的人脸 image_path = 'img/guanyu.jpg' # 已知人脸图片路径 name = "Guan Yu" # 对应的身份名称 image = cv2.imread(image_path) faces = app.get(image) if len(faces) == 1: face = faces[0] embedding = face.embedding # 提取特征向量 face_database[name] = embedding print(f"已添加人脸:{name}") else: print("未检测到人脸或检测到多张人脸,请检查图片") # 保存数据库 with open(database_path, 'wb') as f: pickle.dump(face_database, f) print("人脸数据库已保存") ``` ## 视频中人脸识别 ### 代码 ```python import cv2 import pickle import numpy as np from insightface.app import FaceAnalysis from sklearn.metrics.pairwise import cosine_similarity import time import os import subprocess import threading from queue import Queue, Empty from tqdm import tqdm import torch # 检查是否可以使用GPU DEVICE = 'cuda:0' if torch.cuda.is_available() else 'cpu' # 设置 FFmpeg 路径 FFMPEG_PATH = r"C:\ProgramData\chocolatey\lib\ffmpeg\tools\ffmpeg\bin\ffmpeg.exe" class VideoProcessor: def __init__(self, input_path: str, output_path: str, face_database: dict, batch_size: int = 4, num_workers: int = 4): self.input_path = input_path self.output_path = output_path self.temp_output_path = output_path.replace('.mp4', '_temp.mp4') self.face_database = face_database self.batch_size = batch_size self.num_workers = num_workers # 初始化 InsightFace self.app = FaceAnalysis(providers=['CUDAExecutionProvider', 'CPUExecutionProvider']) self.app.prepare(ctx_id=0, det_size=(640, 640)) # 初始化队列 self.frame_queue = Queue(maxsize=30) self.result_queue = Queue(maxsize=30) # 获取视频信息 self.cap = cv2.VideoCapture(input_path) self.fps = self.cap.get(cv2.CAP_PROP_FPS) self.frame_width = int(self.cap.get(cv2.CAP_PROP_FRAME_WIDTH)) self.frame_height = int(self.cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) self.total_frames = int(self.cap.get(cv2.CAP_PROP_FRAME_COUNT)) # 创建视频写入器 self.writer = cv2.VideoWriter( self.temp_output_path, cv2.VideoWriter_fourcc(*'mp4v'), self.fps, (self.frame_width, self.frame_height) ) # 存储检测到的人脸信息 self.detected_faces = {} self.face_lock = threading.Lock() # 添加处理状态标志 self.processing = True def read_frames(self): """读取视频帧的线程函数""" frame_count = 0 pbar_read = tqdm(total=self.total_frames, desc="读取帧", position=0, leave=True) while self.processing: ret, frame = self.cap.read() if not ret: break self.frame_queue.put((frame_count, frame)) frame_count += 1 pbar_read.update(1) pbar_read.close() self.frame_queue.put(None) # 发送结束信号 def process_frame(self, frame_data): """处理单个视频帧""" if frame_data is None: return None frame_count, frame = frame_data current_time = time.time() # 每5帧处理一次人脸检测 if frame_count % 5 == 0: faces = self.app.get(frame) current_faces = {} for face in faces: face_embedding = face.normed_embedding bbox = face.bbox.astype(int) # 人脸识别 best_match = None best_similarity = -1 for name, db_embedding in self.face_database.items(): similarity = cosine_similarity([face_embedding], [db_embedding])[0][0] if similarity > best_similarity: best_similarity = similarity best_match = name if best_match is not None and best_similarity > 0.5: current_faces[best_match] = { 'bbox': bbox, 'last_seen': current_time } # 更新检测到的人脸信息 with self.face_lock: self.detected_faces.update(current_faces) # 移除超时的人脸 faces_to_remove = [] for name, info in self.detected_faces.items(): if current_time - info['last_seen'] > 0.5: # 0.5秒超时 faces_to_remove.append(name) for name in faces_to_remove: self.detected_faces.pop(name) # 绘制识别框 with self.face_lock: for name, info in self.detected_faces.items(): bbox = info['bbox'] cv2.rectangle(frame, (bbox[0], bbox[1]), (bbox[2], bbox[3]), (0, 255, 0), 2) cv2.putText(frame, name, (bbox[0], bbox[1] - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2) return frame_count, frame def process_frames(self): """处理视频帧的线程函数""" while self.processing: try: frame_data = self.frame_queue.get(timeout=1.0) if frame_data is None: self.result_queue.put(None) break result = self.process_frame(frame_data) if result is not None: self.result_queue.put(result) except Empty: continue except Exception as e: print(f"\n处理帧时出错: {str(e)}") break def write_frames(self): """写入处理后的帧的线程函数""" processed_frames = {} next_frame_to_write = 0 remaining_frames = self.total_frames timeout_counter = 0 pbar_write = tqdm(total=self.total_frames, desc="写入帧", position=1, leave=True) while remaining_frames > 0 and self.processing: try: result = self.result_queue.get(timeout=1.0) if result is None: if len(processed_frames) == 0: break timeout_counter += 1 if timeout_counter > 10: print("\n警告:部分帧可能未处理完成") break continue timeout_counter = 0 frame_count, frame = result processed_frames[frame_count] = frame while next_frame_to_write in processed_frames: self.writer.write(processed_frames[next_frame_to_write]) del processed_frames[next_frame_to_write] next_frame_to_write += 1 remaining_frames -= 1 pbar_write.update(1) except Empty: if len(processed_frames) > 0: available_frames = sorted(processed_frames.keys()) if available_frames[0] == next_frame_to_write: self.writer.write(processed_frames[next_frame_to_write]) del processed_frames[next_frame_to_write] next_frame_to_write += 1 remaining_frames -= 1 pbar_write.update(1) continue except Exception as e: print(f"\n写入帧时出错: {str(e)}") break if processed_frames: print("\n处理剩余帧...") for frame_count in sorted(processed_frames.keys()): self.writer.write(processed_frames[frame_count]) pbar_write.update(1) remaining_frames -= 1 pbar_write.close() def combine_audio(self): """合并视频和音频""" try: command = [ FFMPEG_PATH, '-i', self.temp_output_path, '-i', self.input_path, '-c:v', 'copy', '-c:a', 'aac', '-strict', 'experimental', '-y', self.output_path ] print("执行音频合并...") result = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) if result.returncode == 0: print("音频合并成功!") return True else: print("FFmpeg 错误:") print(result.stderr) return False except Exception as e: print(f"音频合并出错: {str(e)}") print(f"临时文件保留在: {self.temp_output_path}") return False def process_video(self): """处理整个视频""" print(f"\n开始处理视频: {self.input_path}") print(f"总帧数: {self.total_frames}") start_time = time.time() try: # 创建线程 threads = [] # 读取帧的线程 read_thread = threading.Thread(target=self.read_frames) threads.append(read_thread) # 处理帧的线程池 process_threads = [] for _ in range(self.num_workers): t = threading.Thread(target=self.process_frames) process_threads.append(t) threads.append(t) # 写入帧的线程 write_thread = threading.Thread(target=self.write_frames) threads.append(write_thread) # 启动所有线程 for t in threads: t.start() # 设置超时时间(秒) timeout = 300 # 5分钟 start = time.time() # 等待所有线程完成 for t in threads: remaining = timeout - (time.time() - start) if remaining <= 0: print("\n处理超时,强制结束...") self.processing = False break t.join(timeout=remaining) # 检查是否所有线程都已结束 for t in threads: if t.is_alive(): print("\n强制结束未完成的线程...") self.processing = False except Exception as e: print(f"\n处理视频时出错: {str(e)}") self.processing = False finally: # 释放资源 self.cap.release() self.writer.release() print("\n开始合并音频...") # 添加音频 self.combine_audio() # 删除临时文件 if os.path.exists(self.temp_output_path): os.remove(self.temp_output_path) print("临时文件已删除") end_time = time.time() processing_time = end_time - start_time fps = self.total_frames / processing_time print(f"\n处理完成!") print(f"总用时: {processing_time:.2f} 秒") print(f"平均处理速度: {fps:.2f} FPS") print(f"输出文件: {self.output_path}") if __name__ == "__main__": try: # 加载人脸数据库 print("加载人脸数据库...") with open('face_database.pkl', 'rb') as f: face_database = pickle.load(f) # 设置输入输出路径 input_video = './video/Taoyuan.mp4' output_video = './video/Taoyuan_output.mp4' # 确保输出目录存在 os.makedirs(os.path.dirname(output_video), exist_ok=True) # 创建处理器并处理视频 processor = VideoProcessor( input_path=input_video, output_path=output_video, face_database=face_database, num_workers=4 # 根据CPU核心数调整 ) processor.process_video() except Exception as e: print(f"发生错误: {str(e)}") print(f"发生错误: {str(e)}") ``` 构建了一个视频处理类,将人脸识别和视频处理封装了下,采用多线程是希望能够加快处理速度,感觉还可以降低分辨率提高速度,但视频已经挺糊的就没这么处理。 ### 多线程处理: - 使用独立线程读取视频帧 - 使用线程池并行处理帧 - 使用独立线程写入处理后的帧 ### GPU 加速: - 检测是否可用 GPU - 使用 CUDA 加速(如果可用) ### 批处理: - 使用队列管理帧的处理 - 按顺序写入处理后的帧 ### 内存优化: - 使用队列限制内存使用 - 及时释放处理完的帧 ### 性能优化: - 降低人脸检测频率(每5帧检测一次) - 使用线程锁保护共享资源 ### 调整参数 - num_workers:根据CPU核心数调整 - batch_size:根据可用内存调整 - frame_interval:调整人脸检测频率 ## 输出视频结果
Taoyuan_output
此帖出自
嵌入式系统论坛
点赞
关注
(0)
嵌入式论坛
嵌入式开发
嵌入式技术
嵌入式教程
回复
分享
扫一扫,分享给好友
复制链接分享
链接复制成功,分享给好友
举报
提升卡
变色卡
千斤顶
返回列表
发新帖
回复
您需要登录后才可以回帖
登录
|
注册
发表回复
回帖后跳转到最后一页
活动
更多>>
PI 电源小课堂:集成式半桥驱动IC BridgeSwitch 2, 助力高效永磁同步电机逆变器的设计
Microchip喊你探索dsPIC33A 芯片,70份好礼等你赢!
【瓜分2500元红包】票选2024 DigiKey “感知万物,乐享生活”创意大赛人气作品TOP3!
DigiKey应用探索站重磅上线!潮流应用,硬核技术探秘,N多干货,一站get!
验证并选择心仪MOSFET,探寻选型奥秘!注册、体验双重好礼等你拿~
免费申请测评 | 泰坦触觉 TITAN Core开发套件
评论有奖:元器件采购的秘密法宝,助你做个自带“松弛感”的职场人!
免费申请测评 | RDK X3机器人开发套件
开源项目
更多>>
用于电池充电器的 LTC1174 降压转换器的典型应用电路
PM8908 单片降压转换器的典型应用
具有 400kHz 电荷泵开关的 LT8494EFE 宽输入和输出范围 SEPIC 转换器的典型应用电路
TCR2BF15、200mA、1.5V 输出电压 CMOS 低压降稳压器的典型应用,在 SMV(SOT-25) 中具有自动放电功能
通用CH340下载电路
DV330021,dsPICDEM MCSM 开发板套件旨在在开环或闭环(电流控制)模式下控制单极和双极步进电机
使用 ON Semiconductor 的 CS5203A-1 的参考设计
STC8G扩展版_温湿度扩展模块
LT1021BMH-5 用于处理更高负载电流的电压基准的典型应用
DER-744 - 基于LinkSwitch-XT2的8W宽范围输入、双输出、非隔离反激式转换器
随便看看
信号线等长
[attach]879114[/attach]我想添加差分信号,新建类,为什么我没有网络标签跟我选,现在是什么情况,该怎么办,求解答。
《Linux内核深度解析》-进程管理
【RainbowLink USB 协议转换器】评测1开箱篇:疑惑电源逻辑
晒WEBENCH设计的过程+设计低通滤波器
MSP430学习心得笔记之一:关于Clock
modelsim仿真
我的ST Nucleo F091RC也收到了
求职英语(三):教育经历英语词汇大全
查找数据手册?
搜索
EEWorld Datasheet 技术支持
热门标签
源代码
单片机
放大器
TI
ST
电源
分立器件
传感器
测试测量
模拟
蓄电池充放电电源
比特币挖矿机
交流耐压试验
逆压电效应
导电陶瓷
功率电阻
DBR激光器
移动硬盘
特高压
CPU
相关文章
更多>>
消息称 Arm 正探索收购半导体设计公司 Ampere Computing
1 月 9 日消息,彭博社今日报道称,软银集团及其控股子公司 Arm 正在探讨收购 Ampere Computing 的可能。IT之家注:Ampere 是甲骨文支持的半导体设计公司。 知情人士称,A
斥资3.2亿进军太空领域!丰田章男:未来出行不应局限于汽车
1月9日消息,丰田汽车通过其子公司Woven by Toyota对日本太空航天公司Interstellar Technologies进行了70亿日元(约合4400万美元)的投资,并获得了该公司执行董
汉王展示全球首款磁容芯片:支持8192级压感
1月9日消息,汉王科技在CES 2025全球消费电子展上首次公开展示了全球首颗EMC磁容触控双模芯片——HW0888。 据悉,HW0888同时支持无源电磁笔和电容触控,具有8192级压感和多指触控功
瑞萨电子介绍与本田合作 SDV SoC 细节:台积电 3nm 制程,2000 TOPs AI 算力
美光新加坡 HBM 内存先进封装工厂动工,2026 年投运
美国CDN巨头Akamai宣布2026年6月30日停止在中国服务
三星电子 2024 年第四季度营业利润 6.5 万亿韩元同比增长 130.5% 仍不及市场预期
Teledyne e2v的LS1046和LX2160宇航级处理器,用于宇航应用中的数据压缩
Siri窃听?苹果强调从未出售用户数据
佳明和高通推出新一代数字座舱解决方案,搭载骁龙座舱平台至尊版
新帖速递
STM32和无源蜂鸣器播放声音的问题
车规级AECQ200介绍,混合铝电解电容器的选择
嵌入式教程_DSP技术_DSP实验箱操作教程:2-28 搭建轻量级WEB服务器实验
OPA847IDBVR运放器国产替代
AG32VF407测试UART
【得捷电子Follow Me第二期】第一章 收到货物的分享
请问这个红外接收头是什么型号?能用哪个型号代替?谢谢
出售全新未拆封ZYNQ 7Z020 FPGA核心板
用在锂电池供电的水表设置上的LORA模块,当有100块水表集中安装在一个楼道内时,节能
请问一下,当某个端口被设置为 RX0后,这个端口的输入输出方向还有必要设置吗
今年怎么这么难,比疫情时还难,三十了面临失业好迷茫
请教稳压管测试问题
【小华HC32F448测评】关于小华半导体的UART中断发送和PRINTF构造和重定向
【BIGTREETECH PI开发板】 HDMI输出测试
【BIGTREETECH PI开发板】+08.音频测试(zmj)
英飞凌5V二氧化碳传感器:工程师实测集锦第6期
英飞凌 PAS CO2精彩测评出炉,来看看网友测评的十八般武艺!
本期看英飞凌XENSIV™ PAS CO2传感器基于C的单片机驱动实现
查看 »
答题赢好礼,PI电源小课堂第3期来啦!
本期内容:集成式半桥驱动IC BridgeSwitch 2, 助力高效永磁同步电机逆变器的设计
活动时间:即日起-2月28日
看视频答题即可赢取京东卡!
查看 »
Microchip喊你探索 dsPIC33A 芯片,70份好礼等你赢!
活动时间:即日起-1月26日
活动奖励:随身Wi-Fi、家用多功能电烤箱、20000mAh充电宝、50元京东卡
查看 »
【瓜分2500元红包】票选2024 DigiKey “感知万物,乐享生活”创意大赛人气作品TOP3!
活动时间:即日起——2025年1月17日
查看 »
DigiKey应用探索站重磅上线!潮流应用,硬核技术探秘,N多干货,一站get!
当月好物、热门技术资源、潮流应用技术、特色活动、DigiKey在线实用工具,干货多多~
查看 »
本周精选下载推荐:电源管理基础Dummies
本周小编给大家带来一本超简单、超干货的电子书——《电源管理基础Dummies》!内容深入浅出,排版舒服简洁,分分钟能get到电源管理最核心的知识内容。
查看 »
下载资料赢好礼!看Vicor模块化电源解决方案如何推动创新
活动时间:即日起-2024年12月31日
如何参与:点击活动页内您想了解的模块,找到资料下载即可参与抽奖,活动结束后统一发奖!
查看 »
验证并选择心仪MOSFET,探寻选型奥秘!注册、体验双重好礼等你拿~
MOSFET 选型有点难
选N沟道MOSFET?还是选P沟道MOSFET?
封装如何选:不同封装尺寸有不同的热阻和耗散功率。
瞬态散热更严苛,热设计需要如何处理?
用东芝在线电路仿真器,一键解锁MOSFET选型的秘密!
查看 »
关闭
站长推荐
1
/8
电子工程世界版权所有
京B2-20211791
京ICP备10001474号-1
电信业务审批[2006]字第258号函
京公网安备 11010802033920号
Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复
返回顶部
返回列表
论坛首页
版块列表
专业技术中心
TI技术论坛
ST传感器与低功耗无线技术论坛
ADI参考电路
DigiKey得捷技术专区
ADI · 世健工业技术
电子技术交流
嵌入式系统
单片机
国产芯片交流
电机驱动控制
FPGA/CPLD
模拟电子
电源技术
PCB技术
RF/无线
传感器
综合技术交流
下载中心专版
大学堂专版
测评中心专版
创意与实践
电子竞赛
DIY/开源硬件专区
淘e淘
创意市集
行业应用
汽车电子
移动便携
医疗电子
工控电子
安防电子
休息一下
聊聊、笑笑、闹闹
工作这点儿事
为我们提意见&公告
EEWorld颁奖专区
信息发布
最新帖子
最新帖子
最新回复
精华
消灭零回复
测评中心
活动中心
积分兑换
E金币兑换
芯积分
厂商专区
TI技术论坛
ST传感器与低功耗无线技术论坛