当前位置: 首页 > news >正文

MTCNN 人脸识别

前言 

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

 MTCNN Script

import argparse
import cv2
from mtcnn import MTCNN
import os

class 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_image

    def 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

    @staticmethod
    def _load_image(path):
        """加载图像并转换为RGB格式"""
        if not os.path.exists(path):
            return None
        image = cv2.imread(path)
        return cv2.cvtColor(image, cv2.COLOR_BGR2RGB) if image is not None else None

    @staticmethod
    def _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 plt
            plt.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.py
    ros::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 way
        loop_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++与命令行、系统时间的交互。——实际上,不少我们熟知的、主观上认为独立的计算机概念,可能都以类似的方式彼此连接着。

相关文章:

  • 网页设计师月薪多少优化公司怎么优化网站的
  • 定制开发电商网站建设多少钱楚雄百度推广电话
  • vue发布停运公告温州seo优化公司
  • 长沙高端网站建设互联网营销顾问
  • 水泵行业网站怎么做文山seo公司
  • 个人手机版网站建设南宁网络推广热线
  • 对于GAI虚假信息对舆论观察分析
  • 月之暗面开源:多模态推理模型(激活2.8B) Kimi-VL-A3B-Thinking
  • PCDN收益高低的关键因素
  • Python p_tqdm包介绍
  • 2025年土建施工员考试题库及答案
  • js中较为不错的对象内置方法
  • Cribl 通过Splunk search collector 来收集数据
  • 【时时三省】(C语言基础)选择结构程序综合举例
  • 第十五届蓝桥杯C/C++B组国赛真题讲解(分享去年比赛的一些真实感受)
  • 什么是回表?哪些数据库存在回表?
  • dcsdsds
  • ROS2:命令行学习
  • AUTOSAR图解==>AUTOSAR_SWS_MemoryMapping
  • sql server分析表大小
  • 《Python星球日记》第27天:Seaborn 可视化
  • 单片机基础知识-STM32
  • [MSPM0开发]之二MSPM0G3507之IOMUX功能概述(基于driverlib库)
  • SPORT(Serial Port)接口
  • 2.4goweb加解密和jwt
  • 物美“外贸转内销”极速绿色通道正式开启