欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

基于ROS的OPCV的人脸识别

程序员文章站 2022-07-14 22:17:06
...

人脸检测采用基于 Haar 特征的 AdaBoost 算法,由于 Haar特征数量庞大,用常规方式计算其特征值的计算量大、占用资源多、耗时较长,因此,可以借助积分图的方式来计算 Haar 特征值,可以大大提高计算效率。借助积分图方式进行人脸 Haar 特征识别的总体思路是将图像中的 Haar 特征( 矩形特征) 提取出来并计算出积分图像,得到的积分图像与人脸的积分图像对比,符合人脸特征的区域则被标记起来。

2 OpenCV 人脸检测原理

OpenCV 目标检 测 的 方 法 是 利 用 样 本 的 Haar特征进行分类器训练,由弱分类器到强分类器,得到级 联 boosted 分 类 器 ( Cascade Classification) 。Haar-like 算法原理介绍如下。

2. 1 Haar-like 特征

由三类 Haar 特征( 边缘特征、线性特征、中心特征) 组合成特征模板。特征模板内有白色和黑色两种矩形,并定义该模板的特征值为白色矩形像素之和减去黑色矩形像素之和。Haar 特征值反映了图像的灰度变化情况。人的一些脸部特征能简单的由矩形描述,例如: 眼睛的颜色要比脸颊颜色要深,鼻梁两侧的颜色比鼻梁的颜色要深,嘴巴的颜色要比周围颜色要深等。但是单个 Haar-like 特征的分类能力很弱,矩形特征只能描述一些简单的特征图形,还需要利用特定的级联算法将简单Haar-like 特征应用于目标的检测。Haar-like 特征下图 。

基于ROS的OPCV的人脸识别

2.2 图像积分图

利用图像积分图可以快速得到图像中任意矩形的像素和,大大提高了计算矩形相应特征值的速度,是 Haar 分类器能够实时检测人脸的保证。积分图像是将图像左上侧的全部像素进行累加计算,并将图像中的每一个像素替换成所求得的和。在Haar - like 分类器的训练和检测过程中都需要计算当前子图像特征值,积分图算法求出图像中所有区域像素之和只需要遍历一次,解决了算法的耗时问题。构造的积分图如下图 。

基于ROS的OPCV的人脸识别

图 2 中由角标 L1、L2、L3、L4四个像素所表示的矩形区域 D 像素和为:

SumD= L4+ L1-L2-L3;

2.3 AdaBoost 算法

AdaBoost 算法就是一种基于级联分类模型在Haar 特征上构建多个简单的分类器,允许设计者不断加入新的“弱分类器”。首先对每个样本的权值分布进行初始化,如果有 N 个样本,则将每个训练样本赋予相同的权重 1 /N,随后训练弱分类器。在具体训练过程中,如果某个样本已经被准确分类,那么在下一个训练集的构造过程中,其权重将会被降低; 相反,如果某个样本点没有被准确分类,其权重将会升高。与此同时,得到弱分类器相对应的话语权。在结束对各个弱分类器的训练过程后,分类误差率小的弱分类器拥有较大话语权,在最终的分类函数中起着较大决定作用,而分类误差率大的弱分类器拥有较小的话语权,在最终的分类函数中起着较小决定作用。其次,更新权值后的样本集将被用于训练下一个分类器,整个训练过程不断进行迭代。最后,若干个训练后的弱分类器组合成一个强分类器,而一个级联分类器将多个强分类器连接在一起并进行操作。

由于每一个强分类器对负样本的判别准确度非常高,所以检测到负例样本,便不再继续调用后面的强分类器,减少了大量的检测时间。因为一张图像中的待检测区域大部分都是负例样本,级联分类器在分类器的初期就不会进行很多负例样本的复杂检测,所以级联分类器的速度是非常快的; 只有正例样本才会被送到下一个强分类器进行再次检验,这样就保证了最后输出的正例样本的伪正( false positive) 的可能性非常低。级联分类模型见下图。

基于ROS的OPCV的人脸识别

从上面所述内容我们可以总结Haar分类器训练的五大步骤:

1、准备人脸、非人脸样本集;

2、计算特征值和积分图;

3、筛选出T个优秀的特征值(即最优弱分类器);

4、把这个T个最优弱分类器传给AdaBoost进行训练。

5、级联,也就是强分类器的强强联手。

以20*20窗口为例,就有78,460的特征数量,筛选出T个优秀的特征值(即最优弱分类器),然后把这个T个最优弱分类器传给AdaBoost进行训练得到一个强分类器

参考:https://blog.csdn.net/qq_27806947/article/details/84108793

摄像头文件安装参考:https://mp.csdn.net/console/editor/html/103929781

cd ~/catkin_ws/src

git clone https://github.com/bosch-ros-pkg/usb_cam.git

roslaunch usb_cam usb_cam-test.launch

打开摄像头

新建文件功能文件包

catkin_create_pkg cv_bridge_tutorial_cpp cv_bridge image_transport roscpp sensor_msgs std_msgs

cd ./cv_bridge_tutorial_cpp/src

新建文件sample_cv_bridge_node.cpp

#include <ros/ros.h>
#include <image_transport/image_transport.h>
#include <cv_bridge/cv_bridge.h>
#include <sensor_msgs/image_encodings.h>
#include <std_msgs/Int16.h>
#include <std_msgs/Float64MultiArray.h>
#include <std_msgs/UInt16MultiArray.h>
#include <opencv2/objdetect.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/core.hpp>
 
using namespace std;
using namespace cv;
 
CascadeClassifier face_cascade;
 
static const std::string OPENCV_WINDOW = "Raw Image window";
 
 
class Face_Detector
{
  ros::NodeHandle nh_;
  image_transport::ImageTransport it_;
  image_transport::Subscriber image_sub_;
  ros::Publisher chatter_pub;
  
public:
  Face_Detector()
    : it_(nh_)
  {
    // Subscribe to input video feed and publish output video feed
    image_sub_ = it_.subscribe("/usb_cam/image_raw", 1, 
      &Face_Detector::imageCb, this);
    chatter_pub = nh_.advertise<std_msgs::UInt16MultiArray>("chatter", 100);
    cv::namedWindow(OPENCV_WINDOW);
 
  }
 
  ~Face_Detector()
  {
    cv::destroyWindow(OPENCV_WINDOW);
  }
 
  void imageCb(const sensor_msgs::ImageConstPtr& msg)
  {
 
    cv_bridge::CvImagePtr cv_ptr;
    namespace enc = sensor_msgs::image_encodings;
 
    try
    {
      cv_ptr = cv_bridge::toCvCopy(msg, sensor_msgs::image_encodings::BGR8);
    }
    catch (cv_bridge::Exception& e)
    {
      ROS_ERROR("cv_bridge exception: %s", e.what());
      return;
    }
    
    // Draw an example circle on the video stream
    if (cv_ptr->image.rows > 400 && cv_ptr->image.cols > 600){
 
	    detect_faces(cv_ptr->image);
       //chatter_pub.publish(position_x);
	  }
  }
  
 void detect_faces(cv::Mat img)
  {
    RNG rng( 0xFFFFFFFF );
    std_msgs::Int16 position_x;
    std_msgs::Int16 position_y;
    std_msgs::UInt16MultiArray val;
    int data_x;
    int data_y;
    int lineType = 8;
    Mat frame_gray;
    cvtColor( img, frame_gray, COLOR_BGR2GRAY );
    equalizeHist( frame_gray, frame_gray );
    //-- Detect faces
    std::vector<Rect> faces;
    face_cascade.detectMultiScale( frame_gray, faces );
    if (faces.size()>=1){
      size_t i = 0;
      Point center( faces[i].x + faces[i].width/2, faces[i].y + faces[i].height/2 );
      ellipse( img, center, Size( faces[i].width/2, faces[i].height/2 ), 0, 0, 360, Scalar( 255, 0, 255 ), 4 );    
      data_x = cvRound(faces[i].x + faces[i].width/2);
      data_y = cvRound(faces[i].y + faces[i].height/2);
      position_x.data=data_x;
      position_x.data=data_y;
      val.data.push_back(data_x);
      val.data.push_back(data_y);
      chatter_pub.publish(val);
    }
    imshow(OPENCV_WINDOW,img);
    waitKey(3);
 
  }	
  
 
};
 
 
 
int main(int argc, char** argv)
{
  //从命令行读取必要的信息,注意路径
  CommandLineParser parser(argc, argv,
                             "{help h||}"
                             "{face_cascade|/home/jankin/dashgo_ws/src/cv_bridge_tutorial_pkg/src/haarcascade_frontalface_alt.xml|Path to face cascade.}");
    parser.about( "\nThis program demonstrates using the cv::CascadeClassifier class to detect objects (Face + eyes) in a video stream.\n"
                  "You can use Haar or LBP features.\n\n" );
    parser.printMessage();
    String face_cascade_name = parser.get<String>("face_cascade");
 
    //-- 1. Load the cascades
    if( !face_cascade.load( face_cascade_name ) )
    {
        cout << "--(!)Error loading face cascade\n";
        return -1;
    };
 
  ros::init(argc, argv, "Face_Detector");
  Face_Detector ic;
  ros::spin();
  return 0;
}

 CMakeLists.txt文件

include_directories(
# include
  ${catkin_INCLUDE_DIRS}
  ${OpenCV_INCLUDE_DIRS}
)

add_executable(sample_cv_bridge_node src/sample_cv_bridge_node.cpp)
 
target_link_libraries(sample_cv_bridge_node
   ${catkin_LIBRARIES}
   ${OpenCV_LIBRARIES}
 )
 
include_directories(${catkin_INCLUDE_DIRS} ${OpenCV_INCLUDE_DIRS})

基于ROS的OPCV的人脸识别

相关标签: Linux linux