ROS人脸检测 使用webcam实现

github地址https://github.com/ngunauj/facedetection

熟悉ros环境。ubuntu16.04 + ros kinetic版本。使用笔记本自带摄像头,完成人脸的实时检测。代码可能会更改,具体以github上的代码为主。

camera_subscribe.cpp 订阅camera发出的图片信息,然后对Mat 类型的图片进行每一帧图片的人脸检测,人脸检测代码参考opencv的开源代码。
/* ***********************************************
Author        :guanjunace@foxmail.com
Created Time  :2017年07月10日 星期一 10时43分26秒
File Name     :camera_subscribe.cpp
************************************************ */
#include <iostream>
#include <ros/ros.h>
#include <image_transport/image_transport.h>
#include <cv_bridge/cv_bridge.h>
#include <sensor_msgs/image_encodings.h>
#include <opencv2/highgui/highgui.hpp>
#include "opencv2/objdetect.hpp"
#include "opencv2/imgproc.hpp"
using namespace std;
using namespace cv;
const string cascadeName = "/usr/share/opencv/haarcascades/haarcascade_frontalface_alt.xml";
const string nestedCascadeName = "/usr/share/opencv/haarcascades/haarcascade_eye.xml";
const double scale = 1.3;
void detectFace(Mat& img, CascadeClassifier& cascade,
        CascadeClassifier& nestedCascade) {
    double t = 0;
    vector<Rect> faces;
    const static Scalar colors[] = {
        Scalar(255,0,0),
        Scalar(255,128,0),
        Scalar(255,255,0),
        Scalar(0,255,0),
        Scalar(0,128,255),
        Scalar(0,255,255),
        Scalar(0,0,255),
        Scalar(255,0,255)
    };
    Mat gray, smallImg;

    cvtColor( img, gray, COLOR_BGR2GRAY );
    double fx = 1 / scale;
    resize(gray, smallImg, Size(), fx, fx, INTER_LINEAR);
    equalizeHist(smallImg, smallImg);
    t = (double)getTickCount();
    cascade.detectMultiScale(smallImg, faces, 1.1, 2, 0
            //|CASCADE_FIND_BIGGEST_OBJECT
            //|CASCADE_DO_ROUGH_SEARCH
            |CASCADE_SCALE_IMAGE,
            Size(30, 30));
    t = (double)getTickCount() - t;
    printf("detection time = %g ms
", t*1000/getTickFrequency());    
    for (size_t i = 0; i < faces.size(); ++i) {
        Rect r = faces[i];
        Mat smallImgROI;
        vector<Rect> nestedObjects;
        Point center;
        Scalar color = colors[i%8];
        int radius;
        double aspect_ratio = (double)r.width/r.height;
        if(0.75 < aspect_ratio && aspect_ratio < 1.3) {
            center.x = cvRound((r.x + r.width*0.5)*scale);
            center.y = cvRound((r.y + r.height*0.5)*scale);
            radius = cvRound((r.width + r.height)*0.25*scale);
            circle(img, center, radius, color, 3, 8, 0);
        } else {
            rectangle(img, cvPoint(cvRound(r.x*scale), cvRound(r.y*scale)),
                    cvPoint(cvRound((r.x + r.width-1)*scale), cvRound((r.y + r.height-1)*scale)),
                    color, 3, 8, 0);
        }
        smallImgROI = smallImg(r);
        nestedCascade.detectMultiScale(smallImgROI, nestedObjects,
                1.1, 2, 0
                |CASCADE_SCALE_IMAGE,
                Size(30, 30) );
        for (size_t j = 0; j < nestedObjects.size(); ++j) {
            Rect nr = nestedObjects[j];
            center.x = cvRound((r.x + nr.x + nr.width*0.5)*scale);
            center.y = cvRound((r.y + nr.y + nr.height*0.5)*scale);
            radius = cvRound((nr.width + nr.height)*0.25*scale);
            circle(img, center, radius, color, 3, 8, 0);
        }

    }
    imshow("result", img);
    waitKey(1);

}
void img_Callback(const sensor_msgs::ImageConstPtr& msg) {
    Mat image ;
    CascadeClassifier cascade, nestedCascade;
    try {
        image = cv_bridge::toCvShare(msg, "bgr8")->image;
        //CascadeClassifier cascade, nestedCascade;
        nestedCascade.load(nestedCascadeName);
        cascade.load(cascadeName);
        detectFace(image, cascade, nestedCascade);
        //Convert an immutable sensor_msgs::Image message to an OpenCV-compatible CvImage, 
        //sharing the image data if possible. 
        //imshow("img", cv_bridge::toCvShare(msg, "bgr8")->image);//IplImage 类型的 mat
        //waitKey(1);
    } catch (cv_bridge::Exception &e) {
        ROS_ERROR("Could not convert from '%s' to 'bgr8'.", msg->encoding.c_str());
    }
    if (!image.empty()) detectFace(image, cascade, nestedCascade);
    else printf("no image!");
}
int main(int argc, char *argv[]) { 
    ros::init(argc, argv, "img_subscribe");
    ros::NodeHandle nh;
    namedWindow("webcamimg");
    startWindowThread();/*
    CascadeClassifier cascade, nestedCascade;
    if (!nestedCascade.load(nestedCascadeName))
        cerr << "WARNING: Could not load classifier cascade for nested objects" << endl;
    if (!cascade.load(cascadeName)) {
        cerr << "ERROR: Could not load classifier cascade" << endl;
        return -1;
       }
*/
    image_transport::ImageTransport it(nh);
    image_transport::Subscriber img_sub = it.subscribe("/webcam/img", 1, &(img_Callback));

    destroyWindow("webcamimg");
    ros::spin();
    return 0;
}

camera_driver代码

/* ***********************************************
Author        :guanjun  guanjunace@foxmail.com
Created Time  :2017/7/8 10:40:13
File Name     :camera_publisher.cpp
************************************************ */
#include <bits/stdc++.h>
#include <ros/ros.h>
#include <image_transport/image_transport.h>
#include <cv_bridge/cv_bridge.h>
#include <sensor_msgs/image_encodings.h>
#include <opencv2/highgui/highgui.hpp>

using namespace std;
using namespace cv;

class WebCam {
 public:
    WebCam (ros::NodeHandle& nh, int video_source = 0)
    : it(nh), 
    cap(video_source) {
        if (!cap.isOpened()) {
            ROS_ERROR("Cannot open the camera!
");
        }
        /*设置主题名和缓冲区*/   
        imgPub = it.advertise("webcam/img", 1);
        /*初始化CvImage智能指针,CvImage为Mat与ROS图像之间转换的载体*/
        frame = boost::make_shared<cv_bridge::CvImage>();
        /*设置ROS图片为BGR且每个像素点用1个字节来表示类似于CV_8U*/
        frame->encoding = sensor_msgs::image_encodings::BGR8;
    }
    /*图像发布函数*/
    int publishImage(){
        /*将摄像头获取到的图像存放在frame中的image*/
        cap >> frame->image;
        /*判断是否获取到图像,若获取到图像,将其转化为ROS图片*/
        if (!(frame->image.empty())){
            frame->header.stamp = ros::Time::now();
            imgPub.publish(frame->toImageMsg());
        }
        return 0;       
    }
 private:    
    /*设置图片节点*/
    image_transport::ImageTransport it;
    /*设置图片的发布者*/
    image_transport::Publisher imgPub;
    /*设置存放摄像头图像的变量*/    
    VideoCapture cap;
    /*设置cvImage的智能指针*/
    cv_bridge::CvImagePtr frame;
};

int main(int argc, char *argv[]) {
    /*初始化节点,并设定节点名*/
    ros::init(argc, argv, "img_publiser");
    /*设置节点句柄*/
    ros::NodeHandle nh;

    /*判断输入参数是否完成*/
    if (argv[1] == NULL){
        ROS_WARN("Please choose the camera you want to use !");
        return 1;
    }
    /*获取打开摄像机的设备号*/
    int video_source = 0;
    int default_p = 0;
    istringstream default_param(argv[1]);
    default_param >> default_p;
    nh.param<int>("video_source", video_source, default_p);

    /*定义摄像机对象*/
    WebCam webcam(nh, video_source);

    /*设置主题的发布频率为10Hz*/
    ros::Rate loop_rate(10);
    /*图片节点进行主题的发布*/
    while (ros::ok()) {
        webcam.publishImage();
        ros::spinOnce();
        /*按照设定的频率来将程序挂起*/
        loop_rate.sleep();
    }
    return 0;
}

 在人脸检测的过程中,随着人脸的移动,有个别帧并不能检测出人脸,考虑以后哦要加个跟踪

原文地址:https://www.cnblogs.com/pk28/p/7146172.html