#include <ros/ros.h>
#include <cv_bridge/cv_bridge.h>
#include <sensor_msgs/image_encodings.h>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/objdetect/objdetect.hpp>
using namespace cv;
static CascadeClassifier face_cascade;
static Mat frame_gray;
static std::vector<Rect> faces;
static std::vector<cv::Rect>::const_iterator face_iter;
void callbackRGB(const sensor_msgs::Image msg)
{
cv_bridge::CvImagePtr cv_ptr;
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;
}
Mat imgOriginal = cv_ptr->image;
// 转换成黑白图像
cvtColor( imgOriginal, frame_gray, CV_BGR2GRAY );
equalizeHist( frame_gray, frame_gray );
// 检测人脸
face_cascade.detectMultiScale( frame_gray, faces, 1.1, 9, 0|CASCADE_SCALE_IMAGE, Size(30, 30) );
// 在彩色原图中标注人脸位置
if(faces.size() > 0)
{
std::vector<cv::Rect>::const_iterator i;
for (face_iter = faces.begin(); face_iter != faces.end(); ++face_iter)
{
cv::rectangle(
imgOriginal,
cv::Point(face_iter->x , face_iter->y),
cv::Point(face_iter->x + face_iter->width, face_iter->y + face_iter->height),
CV_RGB(255, 0 , 255),
2);
}
}
imshow("faces", imgOriginal);
waitKey(1);
}
int main(int argc, char **argv)
{
cv::namedWindow("faces");
ros::init(argc, argv, "demo_cv_face_detect");
ROS_INFO("demo_cv_face_detect");
std::string strLoadFile;
char const* home = getenv("HOME");
strLoadFile = home;
strLoadFile += "/catkin_ws";
strLoadFile += "/src/wpr_simulation/config/haarcascade_frontalface_alt.xml";
bool res = face_cascade.load(strLoadFile);
if (res == false)
{
ROS_ERROR("fail to load haarcascade_frontalface_alt.xml");
return 0;
}
ros::NodeHandle nh;
//ros::Subscriber rgb_sub = nh.subscribe("/kinect2/qhd/image_color_rect", 1 , callbackRGB);
//此处修改为usb摄像头的topic,使用自己电脑进行人脸识别。
ros::Subscriber rgb_sub = nh.subscribe("/usb_cam/image_raw", 1 , callbackRGB);
ros::spin();
return 0;
}
代码功能解读
这段代码是一个基于ROS(机器人操作系统)和OpenCV的人脸检测节点,主要功能如下:
整体功能:订阅ROS环境中的彩色图像话题,对图像进行人脸检测,在检测到的人脸周围绘制紫色矩形框,并实时显示处理后的图像。
核心组件解析:
- 头文件:包含ROS相关库(
ros/ros.h
)、ROS与OpenCV图像转换库(cv_bridge/cv_bridge.h
)、OpenCV图像处理库(opencv2/*
)等,实现ROS与OpenCV的协同工作。 - 全局变量:
face_cascade
(Haar级联分类器,用于人脸检测)、frame_gray
(灰度图像,人脸检测的输入格式)、faces
(存储检测到的人脸区域)。 - 回调函数
callbackRGB
:- 通过
cv_bridge
将ROS图像消息(sensor_msgs::Image
)转换为OpenCV的Mat
格式图像。 - 将彩色图像转为灰度图并进行直方图均衡化(提升检测精度)。
- 使用
detectMultiScale
方法检测人脸,返回人脸区域的矩形坐标。 - 在原始彩色图像上用紫色矩形框标记人脸,并通过
imshow
显示。
- 通过
- 主函数
main
:- 初始化ROS节点(节点名
demo_cv_face_detect
)。 - 加载人脸检测模型(
haarcascade_frontalface_alt.xml
,Haar特征分类器模型文件)。 - 创建ROS订阅者,订阅Kinect2的彩色图像话题(
/kinect2/qhd/image_color_rect
),并绑定回调函数。 - 启动ROS消息循环(
ros::spin()
),持续接收并处理图像。
- 初始化ROS节点(节点名
- 头文件:包含ROS相关库(
如何修改代码以使用电脑摄像头
原代码默认订阅Kinect2的图像话题,若要使用电脑摄像头,需通过ROS的usb_cam
包获取摄像头图像并修改订阅话题,步骤如下:
步骤1:安装usb_cam
包(获取电脑摄像头图像)
usb_cam
是ROS中用于读取USB摄像头图像并发布为ROS话题的功能包,执行以下命令安装:
sudo apt-get install ros-<你的ROS版本>-usb-cam
# 例如ROS Noetic:sudo apt-get install ros-noetic-usb-cam
步骤2:修改代码中的订阅话题
原代码订阅的是Kinect2的话题,需改为usb_cam
发布的电脑摄像头话题。
找到main
函数中的订阅者创建代码:
ros::Subscriber rgb_sub = nh.subscribe("/kinect2/qhd/image_color_rect", 1 , callbackRGB);
修改为usb_cam
的默认图像话题(通常为/usb_cam/image_raw
):
ros::Subscriber rgb_sub = nh.subscribe("/usb_cam/image_raw", 1 , callbackRGB);
步骤3:确认人脸检测模型路径
原代码中模型路径为:
strLoadFile = home;
strLoadFile += "/catkin_ws/src/wpr_simulation/config/haarcascade_frontalface_alt.xml";
- 若你的电脑中存在该路径和文件,可直接使用;
- 若不存在,需自行下载
haarcascade_frontalface_alt.xml
(OpenCV官方提供的人脸检测模型),并修改路径为你的文件实际位置,例如:strLoadFile = "/home/你的用户名/opencv_models/haarcascade_frontalface_alt.xml";
步骤4:编译代码
将修改后的代码放入你的ROS工作空间(如catkin_ws/src
)的功能包中,编译工作空间:
cd ~/catkin_ws
catkin_make
source devel/setup.bash
步骤5:运行程序
启动ROS核心:
roscore
启动
usb_cam
节点(打开电脑摄像头并发布图像话题):rosrun usb_cam usb_cam_node
(若摄像头无法启动,可能需要修改
usb_cam
的参数,如摄像头设备号,参考usb_cam
的官方文档)运行你的人脸检测节点:
rosrun 你的功能包名 demo_cv_face_detect
此时会弹出一个名为faces
的窗口,实时显示电脑摄像头的画面,并在检测到的人脸周围绘制紫色矩形框。
注意事项
- 确保电脑摄像头已正确连接并授予权限(一般用户无需额外权限,若无法访问,可尝试
sudo chmod 777 /dev/video0
,video0
为摄像头设备号)。 - 若检测效果不佳,可调整
detectMultiScale
的参数(如1.1
为缩放因子,9
为最小邻居数),减小缩放因子或降低最小邻居数可提高检测灵敏度(但可能增加误检)。 usb_cam
发布的图像编码默认与原代码兼容(BGR8
),无需修改图像转换部分。