鏡像下載、功能變數名稱解析、時間同步請點擊 阿裡雲開源鏡像站 前言 本文主要學習 ROS機器人操作系統 ,在ROS系統里調用 OpenCV庫 實現人臉識別任務 一、環境配置 1.安裝ROS sudo apt-get install ros-kinetic-desktop-full 2.攝像頭調用 安裝攝像頭 ...
鏡像下載、功能變數名稱解析、時間同步請點擊 阿裡雲開源鏡像站
前言
本文主要學習 ROS機器人操作系統 ,在ROS系統里調用 OpenCV庫 實現人臉識別任務
一、環境配置
1.安裝ROS
sudo apt-get install ros-kinetic-desktop-full
2.攝像頭調用
安裝攝像頭組件相關的包,命令行如下:
sudo apt-get install ros-kinetic-usb-cam
啟動攝像頭,命令行如下:
roslaunch usb_cam usb_cam-test.launch
調用攝像頭成功,如下圖所示:
攝像頭的驅動發佈的相關數據,如下圖所示:
攝像頭 usb_cam/image_raw 這個話題,發佈的消息的具體類型,如下圖所示:
那麼圖像消息裡面的成員變數有哪些呢?
列印一下就知道了!一個消息類型裡面的具體成員變數,如下圖所示:
-
Header:很多話題消息裡面都包含的
消息頭:包含消息序號,時間戳和綁定坐標系
消息的序號:表示我們這個消息發佈是排第幾位的,並不需要我們手動去標定,每次
發佈消息的時候會自動地去累加
綁定坐標系:表示的是我們是針對哪一個坐標系去發佈的header有時候也不需要去配置
-
height:圖像的縱向解析度
-
width:圖像的橫向解析度
-
encoding:圖像的編碼格式,包含RGB、YUV等常用格式,都是原始圖像的編碼格式,不涉及圖像壓縮編碼
-
is_bigendian: 圖像數據的大小端存儲模式
-
step:一行圖像數據的位元組數量,作為數據的步長參數
-
data:存儲圖像數據的數組,大小為step×height個位元組
-
format:圖像的壓縮編碼格式(jpeg、png、bmp)
3.導入OpenCV
在ROS當中完成OpenCV的安裝,命令行如下圖所示:
sudo apt-get install ros-kinetic-vision-opencv libopencv-dev python-opencv
安裝完成
二、創建工作空間和功能包
1.創建工作空間
mkdir -p ~/catkin_ws/src
cd ~/catkin_ws/src
catkin_init_workspace
- 創建完成工作空間後,在根目錄下麵,執行編譯整個工作空間
cd ~/catkin_ws/
catkin_make
-
工作空間中會自動生成兩個文件夾:devel,build
-
devel文件夾中產生幾個setup.*sh形成的環境變數設置腳本,使用source命令運行這些腳本文件,則工作空間中的環境變數得以生效
source devel/setup.sh
- 將環境變數設置到/.bashrc文件中
gedit ~/.bashrc
- 在打開的文件,最下麵粘貼以下代碼即可設置環境變數
source ~/catkin_ws/devel/setup.bash
2.創建功能包
開始創建
cd ~/catkin_ws/src
catkin_create_pkg learning std_msgs rospy roscpp
回到根目錄,編譯並設置環境變數
cd ~/catkin_ws
catkin_make
source ~/catkin_ws/devel/setup.sh
三、人臉識別檢測相關代碼
基於 Haar 特征的級聯分類器檢測演算法
核心內容,如下所示:
- 灰階色彩轉換
- 縮小攝像頭圖像
- 直方圖均衡化
- 檢測人臉
1.python文件
face_detector.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import rospy
import cv2
import numpy as np
from sensor_msgs.msg import Image, RegionOfInterest
from cv_bridge import CvBridge, CvBridgeError
class faceDetector:
def __init__(self):
rospy.on_shutdown(self.cleanup);
# 創建cv_bridge
self.bridge = CvBridge()
self.image_pub = rospy.Publisher("cv_bridge_image", Image, queue_size=1)
# 獲取haar特征的級聯表的XML文件,文件路徑在launch文件中傳入
cascade_1 = rospy.get_param("~cascade_1", "")
cascade_2 = rospy.get_param("~cascade_2", "")
# 使用級聯表初始化haar特征檢測器
self.cascade_1 = cv2.CascadeClassifier(cascade_1)
self.cascade_2 = cv2.CascadeClassifier(cascade_2)
# 設置級聯表的參數,優化人臉識別,可以在launch文件中重新配置
self.haar_scaleFactor = rospy.get_param("~haar_scaleFactor", 1.2)
self.haar_minNeighbors = rospy.get_param("~haar_minNeighbors", 2)
self.haar_minSize = rospy.get_param("~haar_minSize", 40)
self.haar_maxSize = rospy.get_param("~haar_maxSize", 60)
self.color = (50, 255, 50)
# 初始化訂閱rgb格式圖像數據的訂閱者,此處圖像topic的話題名可以在launch文件中重映射
self.image_sub = rospy.Subscriber("input_rgb_image", Image, self.image_callback, queue_size=1)
def image_callback(self, data):
# 使用cv_bridge將ROS的圖像數據轉換成OpenCV的圖像格式
try:
cv_image = self.bridge.imgmsg_to_cv2(data, "bgr8")
frame = np.array(cv_image, dtype=np.uint8)
except CvBridgeError, e:
print e
# 創建灰度圖像
grey_image = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# 創建平衡直方圖,減少光線影響
grey_image = cv2.equalizeHist(grey_image)
# 嘗試檢測人臉
faces_result = self.detect_face(grey_image)
# 在opencv的視窗中框出所有人臉區域
if len(faces_result)>0:
for face in faces_result:
x, y, w, h = face
cv2.rectangle(cv_image, (x, y), (x+w, y+h), self.color, 2)
# 將識別後的圖像轉換成ROS消息併發布
self.image_pub.publish(self.bridge.cv2_to_imgmsg(cv_image, "bgr8"))
def detect_face(self, input_image):
# 首先匹配正面人臉的模型
if self.cascade_1:
faces = self.cascade_1.detectMultiScale(input_image,
self.haar_scaleFactor,
self.haar_minNeighbors,
cv2.CASCADE_SCALE_IMAGE,
(self.haar_minSize, self.haar_maxSize))
# 如果正面人臉匹配失敗,那麼就嘗試匹配側面人臉的模型
if len(faces) == 0 and self.cascade_2:
faces = self.cascade_2.detectMultiScale(input_image,
self.haar_scaleFactor,
self.haar_minNeighbors,
cv2.CASCADE_SCALE_IMAGE,
(self.haar_minSize, self.haar_maxSize))
return faces
def cleanup(self):
print "Shutting down vision node."
cv2.destroyAllWindows()
if __name__ == '__main__':
try:
# 初始化ros節點
rospy.init_node("face_detector")
faceDetector()
rospy.loginfo("Face detector is started..")
rospy.loginfo("Please subscribe the ROS image.")
rospy.spin()
except KeyboardInterrupt:
print "Shutting down face detector node."
cv2.destroyAllWindows()
2.lanuch文件
usb_cam.launch
- 攝像頭啟動文件
<launch>
<node name="usb_cam" pkg="usb_cam" type="usb_cam_node" output="screen" >
<param name="video_device" value="/dev/video0" />
<param name="image_width" value="640" />
<param name="image_height" value="480" />
<param name="pixel_format" value="yuyv" />
<param name="camera_frame_id" value="usb_cam" />
<param name="io_method" value="mmap"/>
</node>
</launch>
face_detector.launch
- 人臉識別啟動文件
<launch>
<node pkg="test2" name="face_detector" type="face_detector.py" output="screen">
<remap from="input_rgb_image" to="/usb_cam/image_raw" />
<rosparam>
haar_scaleFactor: 1.2
haar_minNeighbors: 2
haar_minSize: 40
haar_maxSize: 60
</rosparam>
<param name="cascade_1" value="$(find robot_vision)/data/haar_detectors/haarcascade_frontalface_alt.xml" />
<param name="cascade_2" value="$(find robot_vision)/data/haar_detectors/haarcascade_profileface.xml" />
</node>
</launch>
3.CvBridge
- ROS 與 OpenCV 之間的數據連接是通過 CvBridge 來實現的
- ROS Image Message與 OpenCV Ipllmage 之間連接的一個橋梁
cv_bridge_test.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import rospy
import cv2
from cv_bridge import CvBridge, CvBridgeError
from sensor_msgs.msg import Image
class image_converter:
def __init__(self):
# 創建cv_bridge,聲明圖像的發佈者和訂閱者
self.image_pub = rospy.Publisher("cv_bridge_image", Image, queue_size=1)
self.bridge = CvBridge()
self.image_sub = rospy.Subscriber("/usb_cam/image_raw", Image, self.callback)
def callback(self,data):
# 使用cv_bridge將ROS的圖像數據轉換成OpenCV的圖像格式
try:
cv_image = self.bridge.imgmsg_to_cv2(data, "bgr8")
except CvBridgeError as e:
print e
# 在opencv的顯示視窗中繪製一個圓,作為標記
(rows,cols,channels) = cv_image.shape
if cols > 60 and rows > 60 :
cv2.circle(cv_image, (60, 60), 30, (0,0,255), -1)
# 顯示Opencv格式的圖像
cv2.imshow("Image window", cv_image)
cv2.waitKey(3)
# 再將opencv格式額數據轉換成ros image格式的數據發佈
try:
self.image_pub.publish(self.bridge.cv2_to_imgmsg(cv_image, "bgr8"))
except CvBridgeError as e:
print e
if __name__ == '__main__':
try:
# 初始化ros節點
rospy.init_node("cv_bridge_test")
rospy.loginfo("Starting cv_bridge_test node")
image_converter()
rospy.spin()
except KeyboardInterrupt:
print "Shutting down cv_bridge_test node."
cv2.destroyAllWindows()
四、代碼實測
1.執行命令行
分別在三個終端下運行,命令行如下:
啟動攝像頭
roslaunch robot_vision usb_cam.launch
啟動人臉識別
roslaunch robot_vision face_detector.launch
打開人臉識別視窗
rqt_image_view
2.人臉識別效果
拿了C站官方送的書來進行測試,識別的效果還是相當不錯的,效果如下圖所示:
五、報錯解決
報錯1:E:無法定位軟體包 ros-kinetic-usb-cam
解決方法: 網上下載編譯安裝
$ cd catkin_ws/src
$ git clone https://github.com/bosch-ros-pkg/usb_cam.git
$ cd ~/catkin_ws
$ catkin_make
成功解決:
報錯2:啟動攝像頭報錯
解決方法:輸入以下命令行,再啟動攝像頭
source ~/catkin_ws/devel/setup.bash
成功解決:
報錯3:虛擬機攝像頭沒連接報錯
解決方法:打開虛擬機設置,更改usb版本為3.1
可移動設備將攝像頭設置連接
六、總結
-
在ROS操作系統中調用 OpenCV 完成人臉識別還是比較有意思的,目前圖像處理和人臉識別還是比較常用到的,本文主要記錄學習過程,以及遇到的相關報錯問題進行記錄
-
如何對於特定目標的檢測並顯示出結果?如何優化讓人臉識別的更精準?目前還在朝著這個方向進行思考和探究
原文鏈接:https://blog.csdn.net/m0_61745661/article/details/125578352