news 2026/4/23 16:09:28

13.长视频和短视频的目标追踪(yolo_insightface模型)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
13.长视频和短视频的目标追踪(yolo_insightface模型)

1.视频追踪原理

视频追踪原理如下:

2.环境搭建

该模型的环境搭建其实很简单,具体步骤如下:

2.1 insightface模型环境搭建

步骤 1:创建虚拟环境(推荐,避免依赖冲突)

建议用conda(Anaconda/Miniconda)创建独立环境,也可使用venv

# 1. 安装Anaconda后,创建conda环境(名称自定义,如insightface_env) conda create -n insightface_env python=3.8 # 2. 激活环境 # Windows conda activate insightface_env # Linux/macOS source activate insightface_env
步骤 2:安装 PyTorch(GPU/CPU 版,核心依赖)

InsightFace 基于 PyTorch,需先安装适配的 PyTorch 版本:

  1. 查看系统 CUDA 版本(GPU 用户):
nvcc -V # 如输出CUDA 11.7,则对应安装torch的cu117版本
  1. 安装命令(从 PyTorch 官网复制,示例如下):

GPU 版(CUDA 11.7):

pip3 install torch==2.0.1 torchvision==0.15.2 torchaudio==2.0.2 --index-url https://download.pytorch.org/whl/cu117

3. 验证 PyTorch 安装

import torch print(torch.cuda.is_available()) # GPU版返回True,CPU版返回False
步骤 3:安装 InsightFace
方式 1:pip 安装官方稳定版(推荐)
pip install insightface
方式 2:源码安装(需最新功能 / 修复 bug)
# 克隆源码 git clone https://github.com/deepinsight/insightface.git cd insightface # 安装依赖 pip install -r requirements.txt # 安装库(开发模式) pip install -e .
步骤4:安装额外依赖

InsightFace 依赖onnxruntime(模型推理)、mxnet(部分功能)、opencv-python等,若安装后报错,补充安装:

# 基础依赖 pip install opencv-python pillow numpy onnxruntime-gpu # GPU版onnxruntime # 若CPU版,替换为:onnxruntime # 可选:mxnet(部分旧模型需要) pip install mxnet-cu117 # 对应CUDA 11.7,CPU版用mxnet

步骤5:验证环境是否搭建成功

执行以下代码,测试 InsightFace 核心功能(需先下载预训练模型,首次运行会自动下载):

import insightface import cv2 import time # 1. 初始化模型(首次加载耗时不计入检测耗时) app = insightface.app.FaceAnalysis(name='E:/AI/1.1_track/models/buffalo_s') # ctx_id=0:GPU加速(需装onnxruntime-gpu);ctx_id=-1:CPU app.prepare(ctx_id=0, det_size=(320, 320)) # 2. 读取图片(提前读取,排除IO耗时) img_path = "images/1.png" img = cv2.imread(img_path) if img is None: raise ValueError("图片读取失败,请检查路径") # 3. 多次检测取平均(消除偶然误差) test_times = 100 # 测试次数,越多越精准 total_time = 0.0 for i in range(test_times): start_time = time.time() # 核心检测逻辑 faces = app.get(img) end_time = time.time() # 累加耗时(单位:秒) detect_time = end_time - start_time total_time += detect_time # 打印单次耗时(可选) if i % 10 == 0: print(f"第{i}次检测耗时:{detect_time * 1000:.2f}ms") # 计算平均耗时 avg_time = (total_time / test_times) * 1000 # 转换为毫秒 print(f"\n平均检测耗时:{avg_time:.2f}ms") print(f"检测到人脸数量:{len(faces)}")

2.2 yolov8环境搭建

在2.1搭建环境里运行以下代码即可

pip install ultralytics

3.python代码实现

代码实现如下(代码注释了每个函数的功能):

from ultralytics import YOLO import cv2 import time import numpy as np # import insightface from insightface.app import FaceAnalysis import os # ---------------------- 初始化InsightFace人脸特征提取器 ---------------------- # 修复1:统一使用CPU(报错显示无CUDA,故删除CUDA配置,避免警告) face_app = FaceAnalysis( name='buffalo_s', root='E:/AI/1.1_track', # providers=['CPUExecutionProvider'] # 仅保留CPU,匹配环境实际支持的Provider providers=['CUDAExecutionProvider'] # 根据实际情况选择CPU或GPU ) face_app.prepare(ctx_id=0, det_size=(128, 128), det_thresh=0.5) # ctx_id=-1 det_size=(128, 128) # 修复2:调整已知人脸存储结构(用numpy数组存储特征,避免列表/tuple混淆) known_faces = np.array([]) # 存储特征向量(每行:[face_id, 特征1, 特征2, ..., 特征511]) next_face_id = 0 # 下一个新面孔的ID saves_dir = "images" # 统一人脸保存目录变量(避免函数参数重复) os.makedirs(saves_dir, exist_ok=True) # 确保保存目录存在,防止报错 # 修复3:简化余弦相似度计算(直接处理numpy数组,避免列表索引错误) def cosine_similarity(feat1, feat2): """ 计算已知人脸特征与当前人脸特征的余弦相似度 :param feat1: 已知人脸特征矩阵(shape: [N, 512],N为已知人脸数,512=ID+511维特征) :param feat2: 当前人脸特征向量(shape: [511]) :return: 最大相似度对应的ID、最大相似度值 """ if feat1.size == 0: # 无已知人脸时直接返回 return None, -1.0 # 分离ID列和特征列(避免tuple索引错误的核心修复) known_ids = feat1[:, 0] # 所有已知人脸的ID(第一列) known_feat = feat1[:, 1:] # 所有已知人脸的特征(第2列到最后一列) # 批量计算余弦相似度(numpy矩阵运算,避免循环) dot_product = np.dot(known_feat, feat2) # 点积 norm_known = np.linalg.norm(known_feat, axis=1) # 已知特征的范数(每行1个值) norm_current = np.linalg.norm(feat2) # 当前特征的范数 # 处理范数为0的极端情况(避免除以0) if norm_current == 0 or np.all(norm_known == 0): return None, -1.0 similarities = dot_product / (norm_known * norm_current) max_idx = np.argmax(similarities) # 最大相似度的索引 return known_ids[max_idx].astype(int), similarities[max_idx] # ID转int,匹配预期类型 # 提取人脸特征(保持逻辑,补充异常处理) def get_face_feature(img): """从图像中提取人脸特征(返回numpy数组,避免列表操作)""" try: faces = face_app.get(img) if len(faces) == 0: return None # 返回numpy数组格式的特征向量(511维) return faces[0].embedding.astype(np.float32) except Exception as e: print(f"提取人脸特征失败: {e}") return None # 修复4:人脸识别逻辑(适配numpy数组存储,避免列表插入错误) def recognize_face(face_img, threshold=0.3): """识别人脸,返回对应的ID和相似度""" global known_faces, next_face_id # 提取当前人脸特征 current_feat = get_face_feature(face_img) if current_feat is None: return None, None # 与已知人脸比较 matched_id, max_sim = cosine_similarity(known_faces, current_feat) # 无匹配时,添加新人脸(用numpy拼接,避免列表insert错误) if matched_id is None or max_sim < threshold: matched_id = next_face_id # 构造新特征行:[ID, 511维特征](确保为numpy数组) new_face_row = np.hstack([np.array([matched_id]), current_feat]) # 拼接新行到已知人脸矩阵(首次添加时初始化矩阵) if known_faces.size == 0: known_faces = np.expand_dims(new_face_row, axis=0) else: known_faces = np.vstack([known_faces, new_face_row]) next_face_id += 1 # 更新下一个ID if matched_id is not None and max_sim > threshold and max_sim < (threshold + 30): # 构造新特征行:[ID, 511维特征](确保为numpy数组) new_face_row = np.hstack([np.array([matched_id]), current_feat]) # 拼接新行到已知人脸矩阵(首次添加时初始化矩阵) if known_faces.size == 0: known_faces = np.expand_dims(new_face_row, axis=0) else: known_faces = np.vstack([known_faces, new_face_row]) return matched_id, round(max_sim, 2) # 相似度保留2位小数,优化显示 ############################################### hash对比 ############################################### def calculate_image_hash(image, hash_size=8): """ 计算图片的感知哈希值(基于cv2实现,用于去重) :param image: cv2读取的图片(BGR格式NumPy数组) :param hash_size: 哈希尺寸,默认8x8(生成64位哈希) :return: 哈希值字符串 """ # 转为灰度图 gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # 缩放至(hash_size+1)xhash_size,保留结构特征 resized = cv2.resize(gray, (hash_size + 1, hash_size)) # 计算相邻像素差异(二值化:左侧>右侧为1,否则为0) diff = resized[:, 1:] > resized[:, :-1] # 转换为哈希字符串 return ''.join(str(int(pixel)) for pixel in np.nditer(diff)) def hamming_distance(hash1, hash2): """ 计算两个哈希值的汉明距离(差异位数,用于判断相似度) :param hash1: 第一个哈希字符串 :param hash2: 第二个哈希字符串 :return: 汉明距离(值越小越相似) """ if len(hash1) != len(hash2): raise ValueError("两个哈希值长度必须一致") return sum(c1 != c2 for c1, c2 in zip(hash1, hash2)) def deduplicate_images_by_hash(image_entries, hash_threshold=5): """ 对图片列表按哈希去重(保留第一张相似图片) :param image_entries: 图片条目列表,每个条目为(conf_score, frame_img, frame_num, face_cls) :param hash_threshold: 汉明距离阈值,小于等于此值视为相似图片 :return: 去重后的图片条目列表 """ if not image_entries: return [] deduplicated = [] hash_records = [] # 存储已保留图片的哈希值 for entry in image_entries: # conf_score, frame_img, frame_num, face_cls = entry conf_score, frame_img, frame_num, face_roi_index, face_detections, face_cls = entry # 计算当前图片的哈希值 current_hash = calculate_image_hash(frame_img) # 判断是否与已保留图片相似 is_duplicate = False for existing_hash in hash_records: distance = hamming_distance(current_hash, existing_hash) if distance <= hash_threshold: is_duplicate = True break # 非相似图片则保留,并记录哈希值 if not is_duplicate: deduplicated.append(entry) hash_records.append(current_hash) return deduplicated # 初始化参数 top_n = 1 hash_threshold = 5 # ---------------------- YOLOv8人脸检测与追踪主函数 ---------------------- def yolo_insightface_tracking( video_path, model_path="best.pt", save_output=True, face_conf_thresh=0.4, saves=saves_dir, # 用统一目录变量,避免重复定义 ): # 1. 加载YOLOv8模型 model = YOLO(model_path) print(f"✅ 成功加载YOLO人脸模型:{model_path}") # 2. 打开视频源 cap = cv2.VideoCapture(video_path) if not cap.isOpened(): raise ValueError(f"❌ 无法打开视频源:{video_path}") # 3. 获取视频信息 fps = int(cap.get(cv2.CAP_PROP_FPS)) width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT)) total_duration = total_frames / fps # 总时长(秒) calculated_fps = int(total_frames / total_duration if total_duration > 0 else 0) print(f"📹 视频信息:帧率={fps},分辨率={width}x{height},总帧数={total_frames}") # 存储结构:{track_id: [(人脸置信度, 完整帧, 帧号, 人脸检测类别), ...]} track_frame_data = {} # 存贮最终输出结果 outs = {} # 5. 逐帧处理(修复6:补充current_fps初始化,避免未定义报错) frame_count = 0 print("\n🚀 开始人脸检测与追踪(按 'q' 退出)...") start_time = time.time() while cap.isOpened(): ret, frame = cap.read() if not ret: break frame_count += 1 if frame_count % 30 == 0: # YOLO检测(指定CPU,匹配环境) results = model(frame, conf=face_conf_thresh, iou=0.45)[0]# , device="cpu" face_detections = [] # 处理每个检测框 for result in results: for box in result.boxes: x1, y1, x2, y2 = map(int, box.xyxy[0]) face_detections.append([x1, y1, x2, y2]) # 截取人脸(修复7:确保边界框有效,避免空图像) if x1 >= x2 or y1 >= y2: continue face_img = frame[y1:y2, x1:x2] # 人脸识别与追踪 # end3 = time.time() face_id, similarity = recognize_face(face_img) # 初始化当前追踪ID的存储列表 if face_id not in track_frame_data: track_frame_data[face_id] = [] # (1. outs 加入 id if face_id not in outs: outs[face_id] = {} outs[face_id]['fps_id_list'] = [frame_count] else: outs[face_id]['fps_id_list'].append(frame_count) face_cls = int(box.cls[0]) face_conf = float(box.conf[0]) face_roi = frame[y1:y2, x1:x2] face_roi_index = [x1, y1, x2, y2] if face_roi.size == 0: continue # # 新增当前图片条目到存储列表 current_entry = (face_conf, frame.copy(), frame_count, face_roi_index, face_detections, face_cls) track_frame_data[face_id].append(current_entry) # 按“类别0优先、同类置信度降序”排序 track_frame_data[face_id].sort(key=lambda x: (x[3], -x[0])) # 保留前N个条目(未去重状态) if len(track_frame_data[face_id]) > top_n: track_frame_data[face_id] = track_frame_data[face_id][:top_n] # 资源释放(确保所有窗口关闭) cap.release() cv2.destroyAllWindows() # -------------------------- 核心修改:先去重,再保存 -------------------------- # 1. 对每个追踪ID的图片条目进行哈希去重 deduplicated_track_data = {} for track_id, entries in track_frame_data.items(): deduplicated_entries = deduplicate_images_by_hash(entries, hash_threshold=hash_threshold) deduplicated_track_data[track_id] = deduplicated_entries # 2. 按原格式保存去重后的图片 for track_id, entries in deduplicated_track_data.items(): # for idx, (conf_score, frame_img, frame_num, face_roi_index, face_detections, face_cls) in enumerate(entries, 1): # 处理置信度格式(替换小数点为下划线,避免文件系统异常) score_str = f"{conf_score:.2f}".replace(".", "_") # 保存图片 # 1.保存原图 save_primitive_path = os.path.join(saves, f"id_{track_id}_frame_{frame_num}.jpg") cv2.imwrite(save_primitive_path, frame_img) outs[track_id]["oringe_path"] = save_primitive_path # 2. 保存当前帧对应的头像图 # 步骤4:人脸检测(检测类别0和1) face_results = model(frame_img, conf=face_conf_thresh, iou=0.45)[0] if not face_results.boxes: continue x1, y1, x2, y2 = face_roi_index img = frame_img[y1:y2, x1:x2] saves_img_path = os.path.join(saves, f"id_{track_id}_keys.jpg") cv2.imwrite(saves_img_path, img) outs[track_id]["face_path"] = saves_img_path # 3.保存画了关键帧人头的图片 face_results = model(frame_img, classes=[0, 1], conf=0.3)[0] for box in face_results.boxes: x11, y11, x22, y22 = box.xyxy[0].cpu().numpy().astype(int) cv2.rectangle(frame_img, (x11, y11), (x22, y22), (255, 0, 0), 2) save_range_path = os.path.join(saves, f"id_{track_id}_key_frame_{frame_num}.jpg") cv2.imwrite(save_range_path, frame_img) outs[track_id]["picture_path"] = save_range_path # 统计信息 total_time = time.time() - start_time avg_fps = frame_count / total_time if total_time > 0 else 0.0 print("\n✅ 处理完成!") print(f"📊 统计:总帧数={frame_count},总耗时={total_time:.2f}s,平均帧率={avg_fps:.1f} FPS") print(f"👥 共识别到 {next_face_id} 个不同的人脸") print("帧频率:", calculated_fps) return outs # ---------------------- 运行示例 ---------------------- if __name__ == "__main__": # 配置参数(路径使用原始配置,确保文件存在) VIDEO_SOURCE = r"vedio/2.mp4" # 注意:确认视频路径拼写正确(vedio→video?) MODEL_PATH = "face_best.pt" # 确认best.pt在当前代码目录下 CONF_THRESHOLD = 0.5 start = time.time() try: outs = yolo_insightface_tracking( video_path=VIDEO_SOURCE, model_path=MODEL_PATH, save_output=True, face_conf_thresh=CONF_THRESHOLD, saves = "images" ) for item in outs: print(item, outs[item]) except Exception as e: print(f"❌ 处理出错:{str(e)}") # 修复9:用str(e)确保异常信息完整 finally: end = time.time() print(f"总运行时间:{end - start:.2f}s")

4.实现效果

代码运行的效果如下:

在视频中提取出了5个id,而视频中实际上只有这5个人,我另外运行了3个视频,最后追踪的结果没有重复的头像,也没有漏掉的头像。运行时间和图片中的人头个数成正比,insightface检测每个头像的时间约为0.08s~0.2s之间。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/23 12:53:51

Dify结果过滤难?掌握这3种重排序策略,精准锁定关键信息

第一章&#xff1a;检索重排序的 Dify 结果过滤在构建基于大语言模型的应用时&#xff0c;检索增强生成&#xff08;RAG&#xff09;系统常面临检索结果相关性不足的问题。Dify 作为低代码 AI 应用开发平台&#xff0c;提供了灵活的结果过滤与重排序机制&#xff0c;可有效提升…

作者头像 李华
网站建设 2026/4/23 9:55:22

春节前科技盛宴!小米全家桶扎堆来袭,17 Ultra + 双 Turbo 机皇齐亮相

对数码爱好者来说&#xff0c;年底最期待的莫过于厂商的 “压轴新品秀”。小米这次直接放大招&#xff0c;12 月 14 日曝光的春节前新品清单堪称 “全家桶豪华套餐”—— 从第五代骁龙 8 至尊版加持的小米 17 Ultra&#xff0c;到全球首发天玑 8500 的 REDMI Turbo 5 系列&…

作者头像 李华
网站建设 2026/4/23 9:53:35

构建可持续的自动化测试维护体系

随着敏捷开发与持续集成的普及&#xff0c;自动化测试已成为现代软件工程中不可或缺的一环。然而&#xff0c;许多团队在初期投入自动化后&#xff0c;逐渐面临脚本失效、环境依赖复杂、维护成本高昂等挑战。究其根源&#xff0c;往往是由于缺乏前瞻性的维护策略所致。一、脚本…

作者头像 李华
网站建设 2026/4/23 9:53:08

孩子学编程到底有没有用?这篇文章告诉你!

最近好多家长都在问&#xff1a;现在满大街都在说少儿编程&#xff0c;是不是真的值得学习&#xff1f;我家孩子天天这就知道玩游戏&#xff0c;学这个真的有用吗&#xff1f;说实话&#xff0c;我们能理解大家的焦虑。咱们小时候学的是奥数、英语&#xff0c;现在的孩子起跑线…

作者头像 李华
网站建设 2026/4/23 9:52:53

保姆级教程:用Dify搭建企业级本地知识库,解决数据安全等痛点

本文详细介绍了如何使用Dify搭建企业级本地知识库&#xff0c;解决了远程调用方案的痛点。文章从知识库概念、私有化部署必要性入手&#xff0c;提供了完整的环境准备、文档上传、分段清洗、索引设置等实操步骤&#xff0c;并解答了数据安全、PDF解析、文件格式限制等常见问题。…

作者头像 李华
网站建设 2026/4/23 12:52:10

当学术开题撞上AI革命:Paperzz如何用“智能骨架”重构你的研究起点——一份不靠堆砌术语、只讲真实效率的深度体验报告

Paperzz-AI官网免费论文查重复率AIGC检测/开题报告/文献综述/论文初稿 paperzz - 开题报告https://www.paperzz.cc/proposal 一、开题报告&#xff0c;为什么总让人如临大敌&#xff1f; 你有没有过这样的经历&#xff1f; 深夜两点&#xff0c;电脑屏幕幽幽发亮&#xff0c…

作者头像 李华