MTCNN 人脸识别

前言 

此处介绍强大的 MTCNN 模块,给出demo,展示MTCNN 的 OOP, 以及ROS利用 C++ 节点,命令行调用脚本执行实际工作的思路。

 MTCNN Script

import argparse
import cv2
from mtcnn import MTCNN
import osclass MTCNNProcessor:def __init__(self):"""初始化MTCNN检测器和绘图配置"""self.detector = MTCNN()  # 模型只加载一次self.keypoint_colors = {  # 关键点颜色配置'left_eye': (0, 255, 0),'right_eye': (0, 255, 0),'nose': (255, 0, 255),'mouth_left': (255, 255, 0),'mouth_right': (255, 255, 0)}def process_image(self, input_path="/home/ncut/Pictures/MTCNN_test.jpg", output_path=None):"""完整处理流程入口:param input_path: 输入图像路径:param output_path: 输出图像路径 (None则不保存):return: 带标注的BGR图像数组"""image = self._load_image(input_path)if image is None:raise FileNotFoundError(f"图像文件 {input_path} 不存在或无法读取")results = self.detect_faces(image)annotated_image = self.draw_results(image.copy(), results)if output_path:self._save_image(annotated_image, output_path)return annotated_imagedef detect_faces(self, image):"""执行人脸检测"""return self.detector.detect_faces(image)def draw_results(self, image, results):"""在图像上绘制检测结果"""for result in results:x, y, w, h = result['box']confidence = result['confidence']# 绘制边界框和置信度cv2.rectangle(image, (x, y), (x + w, y + h), (255, 0, 0), 2)cv2.putText(image, f"{confidence:.2%}", (x, y - 10),cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 2)# 绘制关键点for name, pos in result['keypoints'].items():cv2.circle(image, pos, 3, self.keypoint_colors.get(name, (255, 255, 255)), 2)return image@staticmethoddef _load_image(path):"""加载图像并转换为RGB格式"""if not os.path.exists(path):return Noneimage = cv2.imread(path)return cv2.cvtColor(image, cv2.COLOR_BGR2RGB) if image is not None else None@staticmethoddef _save_image(image, path):"""保存图像到指定路径"""cv2.imwrite(path, cv2.cvtColor(image, cv2.COLOR_RGB2BGR))def main():# 命令行参数解析print("in python begin")parser = argparse.ArgumentParser(description='MTCNN人脸检测处理器')parser.add_argument('--input', required=True, help='输入图像路径')parser.add_argument('--output', help='输出图像路径 (可选)')args = parser.parse_args()print("parse succeed")# 创建处理器实例processor = MTCNNProcessor()try:# 执行处理流程result_image = processor.process_image(args.input, args.output)# 可选:显示结果(调试时使用)if os.environ.get('DEBUG_SHOW'):import matplotlib.pyplot as pltplt.imshow(result_image)plt.axis('off')plt.show()except Exception as e:print(f"处理失败: {str(e)}")exit(1)print("python process successfully done")if __name__ == "__main__":main()

上文中,我们在 init部分实现了初始化,包括模型的加载,关键点颜色的硬编码——这部分将直接作用于后续的图像绘制。因为MTCNN模型的帮助,这里我们不需要预处理图像,直接调用方法进行。注意到类中有两个 static method,用修饰符@标识,这是python特有的语法,类似C++中的 static method,独立于变量,由类的方式调用,也许跟单例有关。

实际上,对于MTCNN模块,在环境正确配置后,通过下述语句,能够进行推理

from mtcnn import MTCNN
detector = MTCNN()
image = cv2.cvtColor(cv2.imread('/home/ncut/Pictures/MTCNN_test.jpg'), cv2.COLOR_BGR2RGB)
results = detector.detect_faces(image)
x, y, width, height = result['box']
confidence = result['confidence']

 

ROS Topic subscriber 

C++的sub节点,订阅topic,保存图片,通过命令行方式指定python版本,执行模型推理。

#include <ros/ros.h>
#include <sensor_msgs/Image.h>
#include <cv_bridge/cv_bridge.h>
#include <opencv2/opencv.hpp>
#include <cstdlib>
#include <ctime>
#include <string>
#include <sstream>// 生成唯一文件名(替代 generate_uuid())
std::string generate_unique_id() {static int counter = 0;std::stringstream ss;ss << time(nullptr) << "_" << counter++;  // 时间戳 + 计数器return ss.str();
}void imageCallback(const sensor_msgs::ImageConstPtr& msg) {ROS_INFO("process callback");try {// 转换 ROS 图像消息cv_bridge::CvImagePtr cv_ptr = cv_bridge::toCvCopy(msg, "bgr8");cv::Mat image = cv_ptr->image;// 生成唯一文件名(避免多帧覆盖)std::string uuid = generate_unique_id();std::string temp_path = "/dev/shm/ros_input_" + uuid + ".jpg";std::string output_path = "/dev/shm/ros_output_" + uuid + ".jpg";// 保存输入图像cv::imwrite(temp_path, image);// 构建 Python 调用命令std::string command = "DEBUG_SHOW=1 ""/home/ncut/miniconda3/envs/tf/bin/python /home/ncut/my_ws/src/graduation_design/scripts/MTCNN_photo.py ""--input " + temp_path + " ""--output " + output_path + " ""&";  // attention here// 调用 Python 脚本int ret = std::system(command.c_str());if (ret != 0) {ROS_ERROR("Python脚本调用失败,返回码: %d", ret);return;}ROS_INFO("invoke python script sucessfully");} catch (cv_bridge::Exception& e) {ROS_ERROR("cv_bridge异常: %s", e.what());}
}void MessageCallback()
{ROS_INFO("NOW I am in the callback funciton");return ;
}int main(int argc, char** argv) {ros::init(argc, argv, "MTCNN_sub_photo");ros::NodeHandle nh;// PC test, topic name is camera/image_raw, which matches the video_pub.pyros::Subscriber sub = nh.subscribe("/camera/rgb/image_raw", 2, imageCallback);ROS_INFO("now i will go into the ros::ok() loop");ros::Rate loop_rate(0.04); while(ros::ok()) {ros::spinOnce();    // asynchronous wayloop_rate.sleep();}//ros::spin();system("rm -f /dev/shm/ros_input_*.jpg  /dev/shm/ros_output_*.jpg");return 0;
}

这份代码展示了 ROS 编程的范例,比如 while loop 以 ros::ok()  为循环判断条件。用于生成唯一std::stringstream变量名的time()使用,附加计数器标识图片文件先后存储顺序。在 /dev/shm/共享内存目录保存文件,减少文件读写 I/O, 以及通过 std::stream()方式,运行命令行指令。

In conclusion

这些技巧展示了解决方案的多样性,也展示了C++与命令行、系统时间的交互。——实际上,不少我们熟知的、主观上认为独立的计算机概念,可能都以类似的方式彼此连接着。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/78726.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

01_核心系统下的技术原理解析

15年前&#xff0c;基本上国内的核心系统被C垄断&#xff0c;基本上是IBM的那套东西&#xff0c;场景也是比价复杂&#xff0c;这里不再赘述&#xff0c;TPS太过于庞大&#xff0c;技术上确实比较复杂。为此我这里抛砖引玉&#xff0c;说下对应的支付系统&#xff1a; &#x…

Python 实现最小插件框架

文章目录 Python 实现最小插件框架1. 基础实现项目结构plugin_base.py - 插件基类plugins/hello.py - 示例插件1plugins/goodbye.py - 示例插件2main.py - 主程序 2. 更高级的特性扩展2.1 插件配置支持2.2 插件依赖管理2.3 插件热加载 3. 使用 setuptools 的入口点发现插件3.1 …

电感详解:定义、作用、分类与使用要点

一、电感的基本定义 电感&#xff08;Inductor&#xff09; 是由导线绕制而成的储能元件&#xff0c;其核心特性是阻碍电流变化&#xff0c;将电能转化为磁能存储。 基本公式&#xff1a; 自感电动势&#xff1a; E -L * (di/dt) &#xff08;L&#xff1a;电感值&#xff0c…

运行一次性任务与定时任务

运行一次性任务与定时任务 文章目录 运行一次性任务与定时任务[toc]一、使用Job运行一次性任务1.创建一次性任务2.测试一次性任务3.删除Job 二、使用CronJob运行定时任务1.创建定时任务2.测试定时任务3.删除CronJob 一、使用Job运行一次性任务 1.创建一次性任务 &#xff08;…

对话记忆(Conversational Memory)

一、引言 在与大型语言模型&#xff08;LLM&#xff09;交互的场景中&#xff0c;对话记忆&#xff08;Conversational Memory&#xff09;指的是模型能够在多轮对话中保留、检索并利用先前上下文信息的能力。这一机制使得对话系统不再仅仅是“问答机”&#xff0c;而是能够持…

【HD-RK3576-PI】VNC 远程桌面连接

在当今数字化时代&#xff0c;高效便捷的操作方式是技术爱好者与专业人士的共同追求。对于使用 HD-RK3576-PI微型单板计算机的用户而言&#xff0c;当面临没有显示屏的场景时&#xff0c;如何实现远程操作桌面系统呢&#xff1f;别担心&#xff0c;VNC 远程桌面连接将为你解决这…

【unity游戏开发介绍之UGUI篇】UGUI概述和基础使用

注意&#xff1a;考虑到UGUI的内容比较多&#xff0c;我将UGUI的内容分开&#xff0c;并全部整合放在【unity游戏开发介绍之UGUI篇】专栏里&#xff0c;感兴趣的小伙伴可以前往逐一查看学习。 文章目录 前言1、UI系统的重要性2、UGUI概述2.1 基本定义2.2 UGUI发展历史 3、学习U…

Ubuntu 系统深度清理:彻底卸载 Redis 服务及残留配置

Ubuntu 系统深度清理&#xff1a;彻底卸载 Redis 服务及残留配置 在Ubuntu系统中&#xff0c;Redis是一种广泛使用的内存数据存储系统&#xff0c;用于缓存和消息传递等场景。然而&#xff0c;有时候我们需要彻底卸载Redis&#xff0c;以清理系统资源或为其他应用腾出空间。本…

[ARC196A] Adjacent Delete 题解

假设 n n n 是偶数。如果我们忽略删除相邻数的条件&#xff0c;即可以任选两个数相减&#xff0c;那么答案应该是前 n 2 \frac{n}{2} 2n​ 大的数&#xff08;记作“较大数”&#xff09;的和减去前 n 2 \frac{n}{2} 2n​ 小的数&#xff08;记作“较小数”&#xff09;的和…

Linux上位机开发实践(关于Qt的移植)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 linux平台上面&#xff0c;很多界面应用&#xff0c;都是基于qt开发的。不管是x86平台&#xff0c;还是arm平台&#xff0c;qt使用的地方都比较多。…

”插入排序“”选择排序“

文章目录 插入排序1. 直接插入排序(O(n^2))举例1&#xff1a;举例2&#xff1a;直插排序的"代码"直插排序的“时间复杂度” 2. 希尔排序(O(n^1.3))方法一方法二(时间复杂度更优) 选择排序堆排序直接选择排序 我们学过冒泡排序&#xff0c;堆排序等等。&#xff08;回…

FPGA_BD Block Design学习(一)

PS端开发流程详细步骤 1.第一步&#xff1a;打开Vivado软件&#xff0c;创建或打开一个工程。 2.第二步&#xff1a;在Block Design中添加arm核心&#xff0c;并将其配置为IP核。 3.第三步&#xff1a;配置arm核心的外设信息&#xff0c;如DDR接口、时钟频率、UART接口等。 …

【Python] pip制作离线包

制作离线安装包是一种非常实用的方法&#xff0c;尤其是在网络环境受限或需要在多台机器上部署相同环境时。以下是详细的步骤&#xff0c;帮助您创建一个包含所有依赖项的离线安装包&#xff0c;并在后续环境中复用。 步骤 1&#xff1a;准备工具和环境 确保您有一台可以访问互…

为啥物联网用MQTT?

前言 都说物联网用MQTT&#xff0c;那分别使用Http和Mqtt发送“Hello”&#xff0c;比较一下就知道啦 HTTP HTTP请求报文由请求行、头部字段和消息体组成。一个最简单的HTTP POST请求如下&#xff1a; POST / HTTP/1.1 Host: example.com Content-Length: 5 Content-Type: …

操作系统 ------ 五种IO模型

阻塞IO&#xff1a;一个IO请求操作&#xff0c;准备阶段和复制阶段都会阻塞应用程序&#xff0c;直到操作完全完成 非阻塞IO&#xff1a;一个IO操作请求&#xff0c;先判断准备阶段是否完成&#xff0c;如果未完成立即返回&#xff0c;否则&#xff0c;进入复制阶段&#xff0…

service和endpoints是如何关联的?

在Kubernetes中&#xff0c;Service 和 Endpoints 是两个密切关联的对象&#xff0c;它们共同实现了服务发现和负载均衡的功能。以下是它们之间的关联和工作原理&#xff1a; 1. Service 的定义 Service 是一种抽象&#xff0c;定义了一组逻辑上相关的 Pod&#xff0c;以及用…

程序化广告行业(78/89):多因素交织下的行业剖析与展望

程序化广告行业&#xff08;78/89&#xff09;&#xff1a;多因素交织下的行业剖析与展望 在程序化广告这片充满活力又不断变化的领域&#xff0c;持续学习和知识共享是我们紧跟潮流、实现突破的关键。一直以来&#xff0c;我都渴望能与大家一同探索这个行业的奥秘&#xff0c…

数智化重构供应商管理

当供应链韧性成为核心竞争力&#xff0c;你的供应商管理还在 “摸着石头过河” 吗&#xff1f; 在传统模式下&#xff0c;供应商管理高度依赖人工经验与纸质流程&#xff1a; 入库筛选如“大海捞针”&#xff1a;供应商资质审核停留在Excel表格比对&#xff0c;资质造假、历史…

网络互连与互联网

1.在路由表中找不到目标网络时使用默认路由&#xff0c;默认路由通常指本地网关的地址。 2.OSPF最主要的特征是使用分布式链路状态协议&#xff0c;而RIP使用的是距离向量协议。 3.OSPF使用链路状态公告LSA扩散路由信息 4.内部网关路由协议IGRP是一种动态距离矢量路由协议&a…

Raymarching Textures In Depth

本节课最主要的就是学会hlsl中使用纹理采样 float4 color Texture2DSample(Texobj, TexobjSampler, uv); return color; 课程中的代码&#xff08;没有这张图我就没做&#xff09; 课程代码产生深度的原因是uv偏移&#xff0c;黑色区域会不断向左偏移&#xff0c;直到找到白色…