news 2026/4/18 8:06:03

RetinaFace人脸检测实战:如何导出检测框坐标与关键点坐标的CSV表格

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
RetinaFace人脸检测实战:如何导出检测框坐标与关键点坐标的CSV表格

RetinaFace人脸检测实战:如何导出检测框坐标与关键点坐标的CSV表格

你是不是也遇到过这样的问题:用RetinaFace跑完人脸检测,看到图上画出了漂亮的检测框和五个红点,但真正想拿这些数据做后续分析时——却发现结果只存在图片里,坐标信息根本没保存下来?别急,这篇实战指南就带你从“看得见”走向“拿得到”,手把手教你把每张图里的人脸位置、检测框坐标、五个关键点坐标全部导出成标准CSV表格,方便Excel打开、Python读取、数据库入库,真正实现结构化数据输出。

这不是一个泛泛而谈的模型介绍,而是一份聚焦工程落地的实操手册。我们不讲FPN多层特征融合的数学推导,也不堆砌论文里的指标曲线,只解决你此刻最关心的一个动作:怎么把屏幕上显示的那些点和框,变成一行行可计算、可统计、可复用的数字?全程基于CSDN星图镜像广场提供的「RetinaFace 人脸检测与关键点绘制」预置镜像,开箱即用,无需编译、不用配环境,连conda环境都已为你激活好——你只需要知道哪几行代码改一下,就能让模型不仅“画出来”,还能“吐出来”。


1. 为什么默认不导出坐标?先搞懂脚本在做什么

在动手改代码之前,得先明白当前镜像里那个inference_retinaface.py到底干了什么。它不是黑盒,而是一段清晰、简洁、高度可读的推理逻辑。理解它,是安全修改的第一步。

1.1 原始脚本的核心流程

打开/root/RetinaFace/inference_retinaface.py,你会发现整个流程非常线性:

  1. 加载模型:从ModelScope自动下载并加载iic/cv_resnet50_face-detection_retinaface
  2. 读图预处理:将输入图片转为Tensor,归一化,送入模型;
  3. 模型前向推理:得到原始输出——一个包含多个人脸的列表,每个元素是一个字典,含bbox(4维数组:[x1, y1, x2, y2])、kps(5×2数组:[[x1,y1], [x2,y2], ..., [x5,y5]])和score(置信度);
  4. 可视化绘制:调用OpenCV,在原图上画矩形框、画圆点、标分数;
  5. 保存图片:把画完的图存进face_results/文件夹。

关键就在这里:第3步拿到的bboxkps是纯内存里的Python对象,但脚本到第4步就直接丢给绘图函数了,再没做任何格式化保存。它的设计初衷是“快速验证效果”,而不是“交付结构化数据”。

1.2 坐标数据长什么样?举个真实例子

假设你用一张单人正脸图测试,模型返回的第一个检测结果可能是这样:

{ 'bbox': [128.3, 95.7, 312.6, 289.4], # 左上x, 左上y, 右下x, 右下y 'kps': [ [172.1, 143.5], # 左眼中心 [245.8, 142.9], # 右眼中心 [209.3, 198.2], # 鼻尖 [178.6, 231.7], # 左嘴角 [240.2, 232.1] # 右嘴角 ], 'score': 0.987 }

这组数字就是你要的全部信息。bbox是检测框的精确像素坐标;kps是五个关键点的二维坐标。它们天然就是结构化数据,只需稍作整理,就能写入CSV。


2. 动手改造:三步添加CSV导出功能

我们不需要重写整个脚本,只需在原有逻辑中插入三个轻量级模块:数据收集 → 表头定义 → 文件写入。所有改动都在同一个文件内完成,不影响原有绘图功能,完全向后兼容。

2.1 第一步:在推理循环中收集所有坐标数据

找到脚本中遍历检测结果的for i, det in enumerate(detections):循环(通常在绘图代码之前)。在循环内部,新增一个列表用于暂存每张图的每张脸数据:

# 在 import 语句下方或 main() 函数开头,添加: import csv import os # 在 detections = model(...) 之后、绘图循环之前,初始化空列表: all_face_data = [] # 用于收集所有图片的所有人脸数据 # 找到绘图循环,例如: for i, det in enumerate(detections): bbox = det['bbox'] kps = det['kps'] score = det['score'] # 新增:将当前这张脸的所有坐标打包成一行数据 face_row = { 'image_name': os.path.basename(args.input) if os.path.isfile(args.input) else 'url_image', 'face_id': i + 1, 'score': f"{score:.4f}", 'bbox_x1': f"{bbox[0]:.2f}", 'bbox_y1': f"{bbox[1]:.2f}", 'bbox_x2': f"{bbox[2]:.2f}", 'bbox_y2': f"{bbox[3]:.2f}", 'left_eye_x': f"{kps[0][0]:.2f}", 'left_eye_y': f"{kps[0][1]:.2f}", 'right_eye_x': f"{kps[1][0]:.2f}", 'right_eye_y': f"{kps[1][1]:.2f}", 'nose_x': f"{kps[2][0]:.2f}", 'nose_y': f"{kps[2][1]:.2f}", 'left_mouth_x': f"{kps[3][0]:.2f}", 'left_mouth_y': f"{kps[3][1]:.2f}", 'right_mouth_x': f"{kps[4][0]:.2f}", 'right_mouth_y': f"{kps[4][1]:.2f}", } all_face_data.append(face_row)

这段代码的作用,是把每张检测到的人脸,按字段名(如bbox_x1,left_eye_x)组织成一个字典,并追加到all_face_data列表中。注意:我们用了f"{x:.2f}"统一保留两位小数,既保证精度又提升可读性。

2.2 第二步:定义CSV表头并创建输出文件

在绘图循环结束后、图片保存之前,加入CSV写入逻辑:

# 新增:定义CSV表头(顺序必须与 face_row 字段一致) csv_headers = [ 'image_name', 'face_id', 'score', 'bbox_x1', 'bbox_y1', 'bbox_x2', 'bbox_y2', 'left_eye_x', 'left_eye_y', 'right_eye_x', 'right_eye_y', 'nose_x', 'nose_y', 'left_mouth_x', 'left_mouth_y', 'right_mouth_x', 'right_mouth_y' ] # 新增:构造CSV文件路径(与 face_results 同级,避免混淆) csv_output_path = os.path.join(os.path.dirname(args.output_dir), "detection_results.csv") # 新增:写入CSV with open(csv_output_path, 'w', newline='', encoding='utf-8') as f: writer = csv.DictWriter(f, fieldnames=csv_headers) writer.writeheader() writer.writerows(all_face_data) print(f"[INFO] CSV results saved to: {csv_output_path}") print(f"[INFO] Total faces detected: {len(all_face_data)}")

这里的关键点:

  • csv_output_path被设为与face_results/同级目录,比如你用-d /root/workspace/output_detect,CSV就会生成在/root/workspace/detection_results.csv,逻辑清晰不打架;
  • 使用csv.DictWriter直接写入字典列表,无需手动拼接字符串,安全又简洁;
  • 最后两行打印提示,让你一眼确认是否成功、检测了多少张脸。

2.3 第三步:支持批量图片输入(可选但强烈推荐)

默认脚本只支持单张图(--input),但实际工作中你往往有一整个文件夹的图片。我们只需加几行代码,就能让它批量处理:

# 在参数解析部分(argparse.ArgumentParser),添加新参数: parser.add_argument('--input_dir', '-id', type=str, default=None, help='Directory containing input images (e.g., ./test_images). If provided, --input is ignored.') # 在主逻辑中,替换原来的单图读取逻辑: if args.input_dir and os.path.isdir(args.input_dir): # 批量处理目录下所有 .jpg/.png 图片 image_files = [os.path.join(args.input_dir, f) for f in os.listdir(args.input_dir) if f.lower().endswith(('.jpg', '.jpeg', '.png'))] print(f"[INFO] Found {len(image_files)} images in {args.input_dir}") else: # 单图模式(保持原有逻辑) image_files = [args.input]

然后,把原来处理args.input的整段逻辑(从读图到推理到绘图到写CSV),放进一个for img_path in image_files:循环里即可。这样,一条命令就能处理上百张图,结果统一汇总到一个CSV里。


3. 运行与验证:亲眼看到坐标变成表格

完成上述三步修改后,保存文件。现在,让我们用一次完整的命令来验证效果。

3.1 单图测试:快速确认功能生效

cd /root/RetinaFace conda activate torch25 python inference_retinaface.py --input /root/RetinaFace/test.jpg

执行完毕后,除了看到face_results/test.jpg这张带框和点的图,你还会在/root/RetinaFace/目录下发现一个新文件:detection_results.csv

head -n 5 detection_results.csv查看前五行:

image_name,face_id,score,bbox_x1,bbox_y1,bbox_x2,bbox_y2,left_eye_x,left_eye_y,right_eye_x,right_eye_y,nose_x,nose_y,left_mouth_x,left_mouth_y,right_mouth_x,right_mouth_y test.jpg,1,0.9870,128.30,95.70,312.60,289.40,172.10,143.50,245.80,142.90,209.30,198.20,178.60,231.70,240.20,232.10

成功!所有坐标都以标准CSV格式整齐排列,Excel双击即可打开,Pandas一行pd.read_csv("detection_results.csv")就能加载分析。

3.2 批量处理:处理一个文件夹的实战效果

假设你把100张员工证件照放在/root/workspace/id_photos/下:

python inference_retinaface.py --input_dir /root/workspace/id_photos/ --output_dir /root/workspace/id_results/ --threshold 0.7

几秒钟后:

  • /root/workspace/id_results/里有100张带检测框的图;
  • /root/workspace/detection_results.csv里有100行(或更多,如果有人脸多张)结构化数据;
  • 每行对应一个人脸,字段完整,可直接用于统计平均脸宽、关键点偏移分析、质量筛选等。

4. 进阶技巧:让CSV更实用、更专业

导出只是第一步。为了让这份CSV真正成为你的生产力工具,这里分享几个工程师日常都在用的小技巧。

4.1 添加“人脸宽高比”和“关键点间距”衍生字段

face_row构建阶段,可以顺手计算一些业务强相关的衍生指标:

# 在 face_row = {...} 之后,新增: bbox_w = bbox[2] - bbox[0] bbox_h = bbox[3] - bbox[1] eye_dist = ((kps[1][0] - kps[0][0])**2 + (kps[1][1] - kps[0][1])**2)**0.5 face_row.update({ 'bbox_width': f"{bbox_w:.2f}", 'bbox_height': f"{bbox_h:.2f}", 'bbox_aspect_ratio': f"{bbox_w/bbox_h:.3f}", 'inter_eye_distance': f"{eye_dist:.2f}", })

这样,CSV里就多了bbox_aspect_ratio(判断是否侧脸)、inter_eye_distance(用于标准化关键点)等字段,省去后续用Excel或Python再算一遍的麻烦。

4.2 按置信度自动过滤,只保留高质量结果

如果你只关心高置信度检测,可以在写入前加一道过滤:

# 替换原来的 writer.writerows(all_face_data) high_conf_faces = [row for row in all_face_data if float(row['score']) >= 0.85] writer.writerows(high_conf_faces) print(f"[INFO] Wrote {len(high_conf_faces)} high-confidence faces (score >= 0.85)")

4.3 导出为Excel(.xlsx)而非CSV(可选)

如果团队习惯用Excel且需要多Sheet,可安装openpyxl并替换写入逻辑:

pip install openpyxl

然后用from openpyxl import Workbook创建工作簿,把不同图片的结果写入不同Sheet,甚至加上图表——这已超出本文范围,但方向明确:CSV是起点,不是终点。


5. 总结:从“看见”到“拥有”,才是AI落地的真正开始

回顾整个过程,我们没有碰触模型权重,没有重写网络结构,甚至没有安装新库。我们只是读懂了一段已有代码的意图,在它最自然的数据出口处,轻轻接上一根“导出管道”。这恰恰体现了工程化思维的核心:不追求炫技,而专注打通最后一公里。

通过这篇实战,你现在应该已经掌握:

  • 定位能力:能快速找到推理脚本中坐标数据的原始来源(detections列表);
  • 改造能力:能在不破坏原有功能的前提下,安全地插入数据收集与导出逻辑;
  • 扩展能力:能根据业务需求,灵活添加衍生字段、过滤条件、批量处理等实用特性。

更重要的是,你获得了一种可迁移的方法论:无论下次面对的是YOLO的边界框、SAM的分割掩码,还是Stable Diffusion的潜变量,只要数据在内存里,你就拥有了把它结构化、持久化、产品化的主动权。

技术的价值,从来不在模型有多深,而在于你能否把它变成手边可用的工具。今天,你已经迈出了最关键的一步。

--- > **获取更多AI镜像** > > 想探索更多AI镜像和应用场景?访问 [CSDN星图镜像广场](https://ai.csdn.net/?utm_source=mirror_blog_end),提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/18 8:01:17

C++知识体系全解析

好的,这是一个C知识总结的思维导图的文本结构表示,以帮助梳理核心概念: C 知识体系 1. 基础语法 数据类型 基本类型:int, float, double, char, bool复合类型:数组、结构体 (struct)、联合体 (union)、枚举 (enum) …

作者头像 李华
网站建设 2026/4/18 7:57:30

基于PLC的六层电梯控制系统

目录PLC六层电梯控制系统概述系统核心功能硬件组成示例软件逻辑设计调试与优化要点源码文档获取/同行可拿货,招校园代理 :文章底部获取博主联系方式!PLC六层电梯控制系统概述 PLC(可编程逻辑控制器)六层电梯控制系统是一种基于工…

作者头像 李华
网站建设 2026/4/18 1:17:52

HG-ha/MTools参数详解:CUDA_FULL与DirectML版本选型及显存优化技巧

HG-ha/MTools参数详解:CUDA_FULL与DirectML版本选型及显存优化技巧 1. 开箱即用:现代化AI工具集的第一印象 HG-ha/MTools不是那种需要你敲几十行命令、改七八个配置文件才能跑起来的工具。它更像一个装好电池就 ready 的智能设备——下载安装包&#x…

作者头像 李华
网站建设 2026/4/18 1:29:22

OFA VQA模型提示词指南:What is/How many/Is there等10类问法效果对比

OFA VQA模型提示词指南:What is/How many/Is there等10类问法效果对比 视觉问答(VQA)不是让AI“看图说话”,而是让它真正理解图像内容并回答有逻辑、有依据的问题。OFA模型作为多模态领域的代表性架构之一,其英文VQA能…

作者头像 李华
网站建设 2026/4/17 8:51:30

零基础玩转AcousticSense AI:一键识别16种音乐流派实战教程

零基础玩转AcousticSense AI:一键识别16种音乐流派实战教程 你有没有过这样的时刻:听到一段旋律,心头一震,却说不清它属于爵士、蓝调还是拉丁?朋友发来一首小众电子曲,你翻遍平台标签也找不到准确归类&…

作者头像 李华