【ROS2】OpenCV+ROS 实现人脸识别(Ubantu24.04)
参考鱼香大佬下载安装ROS2OpenCV运行视频。
·
一、环境配置
1.安装ROS2
参考鱼香大佬下载安装ROS2
2.摄像头调用
# 安装摄像头工具
sudo apt install v4l-utils
# 查看摄像头设备
v4l2-ctl --list-devices
# 测试摄像头
sudo apt install cheese
cheese
3.导入OpenCV
# ROS 2 Humble已包含OpenCV,也可单独安装
sudo apt install python3-opencv
OpenCV运行视频
二、创建工作空间和功能包
1.创建工作空间
# 创建新的工作空间
mkdir -p ~/ros2_face_recognition_ws/src
cd ~/ros2_face_recognition_ws/src
2.创建功能包
ros2 pkg create face_recognition --build-type ament_python --dependencies rclpy cv_bridge sensor_msgs std_msgs image_transport
3.安装OpenCV数据文件
# 安装OpenCV数据文件(包含人脸检测器)
sudo apt update
sudo apt install opencv-data
# 检查文件是否安装成功
ls /usr/share/opencv4/haarcascades/haarcascade_frontalface_default.xml
4.创建文件结构
cd face_recognition
mkdir -p launch
mkdir -p face_recognition
三、人脸识别检测相关代码
1. 创建人脸检测节点
cat > face_recognition/face_detector.py << 'EOF'
#!/usr/bin/env python3
import rclpy
from rclpy.node import Node
from sensor_msgs.msg import Image
from std_msgs.msg import String
from cv_bridge import CvBridge
import cv2
import os
class FaceDetector(Node):
def __init__(self):
super().__init__('face_detector')
# 初始化CV Bridge
self.bridge = CvBridge()
# 创建订阅者(摄像头图像)
self.subscription = self.create_subscription(
Image,
'/camera/image_raw',
self.image_callback,
10)
# 创建发布者
self.image_pub = self.create_publisher(Image, '/face_detection/result', 10)
self.status_pub = self.create_publisher(String, '/face_detection/status', 10)
# 加载人脸检测器
self.face_cascade = None
self.load_face_detector()
if self.face_cascade is not None:
self.get_logger().info('🚀 人脸检测节点已启动,等待摄像头数据...')
else:
self.get_logger().error('❌ 人脸检测器加载失败,节点无法正常工作')
def load_face_detector(self):
"""加载人脸检测器,尝试多种路径"""
cascade_paths = [
# OpenCV 4.x 路径
'/usr/share/opencv4/haarcascades/haarcascade_frontalface_default.xml',
# OpenCV 3.x 路径
'/usr/share/opencv/haarcascades/haarcascade_frontalface_default.xml',
# 系统路径
'/usr/local/share/opencv4/haarcascades/haarcascade_frontalface_default.xml',
]
for path in cascade_paths:
if os.path.exists(path):
self.face_cascade = cv2.CascadeClassifier(path)
if not self.face_cascade.empty():
self.get_logger().info(f'✅ 从 {path} 加载人脸检测器')
return
# 如果以上路径都失败,尝试使用cv2.data(如果存在)
try:
# 检查cv2是否有data属性
if hasattr(cv2, 'data'):
cascade_file = cv2.data.haarcascades + 'haarcascade_frontalface_default.xml'
self.face_cascade = cv2.CascadeClassifier(cascade_file)
if not self.face_cascade.empty():
self.get_logger().info('✅ 使用cv2.data加载人脸检测器')
return
except Exception as e:
self.get_logger().warning(f'使用cv2.data失败: {e}')
# 如果还是失败,提供安装建议
self.get_logger().error('❌ 无法加载人脸检测器')
self.get_logger().info('💡 请确保已安装: sudo apt install opencv-data')
self.face_cascade = None
def image_callback(self, msg):
# 检查人脸检测器是否加载成功
if self.face_cascade is None:
return
try:
# 将ROS图像消息转换为OpenCV格式
cv_image = self.bridge.imgmsg_to_cv2(msg, 'bgr8')
except Exception as e:
self.get_logger().error(f'图像转换错误: {str(e)}')
return
# 转换为灰度图像进行人脸检测
gray = cv2.cvtColor(cv_image, cv2.COLOR_BGR2GRAY)
# 人脸检测
try:
faces = self.face_cascade.detectMultiScale(
gray,
scaleFactor=1.1,
minNeighbors=5,
minSize=(30, 30)
)
except Exception as e:
self.get_logger().error(f'人脸检测错误: {str(e)}')
return
# 绘制检测结果
result_image = cv_image.copy()
face_count = len(faces)
for (x, y, w, h) in faces:
cv2.rectangle(result_image, (x, y), (x+w, y+h), (0, 255, 0), 2)
cv2.putText(result_image, 'Face', (x, y-10),
cv2.FONT_HERSHEY_SIMPLEX, 0.9, (0, 255, 0), 2)
# 添加计数信息
cv2.putText(result_image, f'Faces: {face_count}', (10, 30),
cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 0, 0), 2)
# 发布结果图像
try:
result_msg = self.bridge.cv2_to_imgmsg(result_image, 'bgr8')
self.image_pub.publish(result_msg)
except Exception as e:
self.get_logger().error(f'结果图像发布错误: {str(e)}')
# 发布检测状态
status_msg = String()
status_msg.data = f'检测到 {face_count} 张人脸'
self.status_pub.publish(status_msg)
if face_count > 0:
self.get_logger().info(f'👤 检测到 {face_count} 张人脸', throttle_duration_sec=2.0)
def main(args=None):
rclpy.init(args=args)
face_detector = FaceDetector()
# 如果人脸检测器加载失败,直接退出
if face_detector.face_cascade is None:
face_detector.get_logger().error('人脸检测器加载失败,节点退出')
face_detector.destroy_node()
rclpy.shutdown()
return
try:
rclpy.spin(face_detector)
except KeyboardInterrupt:
print('\n🛑 人脸检测节点关闭')
finally:
face_detector.destroy_node()
rclpy.shutdown()
if __name__ == '__main__':
main()
EOF
2. 创建摄像头节点
cat > face_recognition/camera_node.py << 'EOF'
#!/usr/bin/env python3
import rclpy
from rclpy.node import Node
from sensor_msgs.msg import Image
from cv_bridge import CvBridge
import cv2
import numpy as np
class CameraNode(Node):
def __init__(self):
super().__init__('camera_node')
self.bridge = CvBridge()
self.publisher = self.create_publisher(Image, '/camera/image_raw', 10)
self.get_logger().info('📷 正在初始化摄像头...')
# 创建虚拟测试图像
self.virtual_image = self.create_virtual_image()
# 尝试打开物理摄像头
self.cap = None
for i in range(3): # 尝试设备0,1,2
self.get_logger().info(f'尝试打开摄像头设备 /dev/video{i}...')
self.cap = cv2.VideoCapture(i)
if self.cap.isOpened():
# 设置摄像头参数
self.cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
self.cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)
self.cap.set(cv2.CAP_PROP_FPS, 30)
# 让摄像头预热
for _ in range(5):
self.cap.read()
# 验证摄像头能正常读取
ret, frame = self.cap.read()
if ret and frame is not None:
self.get_logger().info(f'✅ 成功打开物理摄像头 /dev/video{i}')
self.get_logger().info(f'📐 图像尺寸: {frame.shape}')
self.use_virtual = False
break
else:
self.cap.release()
self.cap = None
else:
self.cap = None
if self.cap is None:
self.get_logger().warning('❌ 无法打开物理摄像头,使用虚拟摄像头')
self.use_virtual = True
self.timer = self.create_timer(0.033, self.timer_callback) # 30Hz
self.get_logger().info('🎯 摄像头节点已启动')
def create_virtual_image(self):
"""创建虚拟测试图像"""
img = np.ones((480, 640, 3), dtype=np.uint8) * 100
# 绘制彩色矩形模拟场景
cv2.rectangle(img, (100, 100), (200, 200), (255, 0, 0), -1) # 蓝色
cv2.rectangle(img, (300, 150), (400, 250), (0, 255, 0), -1) # 绿色
cv2.rectangle(img, (500, 200), (600, 300), (0, 0, 255), -1) # 红色
# 绘制圆形模拟人脸
cv2.circle(img, (150, 350), 40, (200, 200, 200), -1) # 人脸1
cv2.circle(img, (140, 340), 8, (0, 0, 0), -1) # 左眼
cv2.circle(img, (160, 340), 8, (0, 0, 0), -1) # 右眼
cv2.ellipse(img, (150, 365), (20, 10), 0, 0, 180, (0, 0, 0), 2) # 嘴巴
cv2.circle(img, (450, 350), 35, (200, 200, 200), -1) # 人脸2
cv2.circle(img, (440, 340), 7, (0, 0, 0), -1) # 左眼
cv2.circle(img, (460, 340), 7, (0, 0, 0), -1) # 右眼
cv2.ellipse(img, (450, 365), (15, 8), 0, 0, 180, (0, 0, 0), 2) # 嘴巴
cv2.putText(img, 'Virtual Camera - Face Detection Test', (50, 450),
cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 255), 2)
return img
def timer_callback(self):
if self.use_virtual:
# 使用虚拟图像
msg = self.bridge.cv2_to_imgmsg(self.virtual_image, 'bgr8')
else:
# 使用物理摄像头
ret, frame = self.cap.read()
if ret and frame is not None:
# 确保图像是BGR格式
if len(frame.shape) == 2: # 灰度图
frame = cv2.cvtColor(frame, cv2.COLOR_GRAY2BGR)
msg = self.bridge.cv2_to_imgmsg(frame, 'bgr8')
else:
self.get_logger().warning('摄像头读取失败,使用虚拟图像')
msg = self.bridge.cv2_to_imgmsg(self.virtual_image, 'bgr8')
msg.header.stamp = self.get_clock().now().to_msg()
msg.header.frame_id = 'camera_frame'
self.publisher.publish(msg)
def __del__(self):
if hasattr(self, 'cap') and self.cap and self.cap.isOpened():
self.cap.release()
def main():
rclpy.init()
node = CameraNode()
try:
rclpy.spin(node)
except KeyboardInterrupt:
print('\n🛑 摄像头节点关闭')
finally:
node.destroy_node()
rclpy.shutdown()
if __name__ == '__main__':
main()
EOF
3.创建lanuch文件
cat > launch/face_detection.launch.py << 'EOF'
from launch import LaunchDescription
from launch_ros.actions import Node
def generate_launch_description():
return LaunchDescription([
# 启动摄像头节点
Node(
package='face_recognition',
executable='camera_node',
name='camera_node',
output='screen',
emulate_tty=True
),
# 启动人脸检测节点
Node(
package='face_recognition',
executable='face_detector',
name='face_detector',
output='screen',
emulate_tty=True
),
])
EOF
4. 更新package.xml
cat > package.xml << 'EOF'
<?xml version="1.0"?>
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypelayout="1.0"?>
<package format="3">
<name>face_recognition</name>
<version>0.0.0</version>
<description>Face recognition package using OpenCV and ROS2</description>
<maintainer email="you@example.com">Your Name</maintainer>
<license>Apache-2.0</license>
<depend>rclpy</depend>
<depend>cv_bridge</depend>
<depend>sensor_msgs</depend>
<depend>std_msgs</depend>
<depend>image_transport</depend>
<test_depend>ament_copyright</test_depend>
<test_depend>ament_flake8</test_depend>
<test_depend>ament_pep257</test_depend>
<test_depend>python3-pytest</test_depend>
<export>
<build_type>ament_python</build_type>
</export>
</package>
EOF
5. 更新setup.py
cat > setup.py << 'EOF'
from setuptools import setup
package_name = 'face_recognition'
setup(
name=package_name,
version='0.0.0',
packages=[package_name],
data_files=[
('share/ament_index/resource_index/packages',
['resource/' + package_name]),
('share/' + package_name, ['package.xml']),
('share/' + package_name + '/launch', ['launch/face_detection.launch.py']),
],
install_requires=['setuptools'],
zip_safe=True,
maintainer='Your Name',
maintainer_email='you@example.com',
description='Face recognition package using OpenCV and ROS2',
license='Apache-2.0',
tests_require=['pytest'],
entry_points={
'console_scripts': [
'face_detector = face_recognition.face_detector:main',
'camera_node = face_recognition.camera_node:main',
],
},
)
EOF
6.设置权限并构建
# 设置执行权限
chmod +x face_recognition/face_detector.py
chmod +x face_recognition/camera_node.py
# 构建工作空间
cd ~/ros2_face_recognition_ws
colcon build --packages-select face_recognition
source install/setup.bash
四、代码实测
1.执行命令行
# 使用launch文件启动完整系统
ros2 launch face_recognition face_detection.launch.py
现在系统应该可以正常工作了!如果人脸检测器加载成功,您会看到:
-
✅ 从指定路径加载人脸检测器的消息
-
🚀 人脸检测节点已启动的消息
(如果加载失败,请检查 sudo apt install opencv-data 是否成功安装。)
🎯 系统运行成功!
现在您可以:
1. 查看实时检测结果
# 在另一个终端查看检测结果图像
ros2 run rqt_image_view rqt_image_view
选择 /face_detection/result 话题查看带人脸框的检测结果。
2.查看检测状态
# 查看实时检测状态
ros2 topic echo /face_detection/status
3.人脸识别效果



五、总结
🎊
您已经成功完成了:
-
✅ ROS 2环境配置
-
✅ OpenCV集成
-
✅ 摄像头数据采集
-
✅ 实时人脸检测
-
✅ ROS话题通信
-
✅ 完整的系统集成
更多推荐



所有评论(0)