1 資料
從本文開始,我們用四篇文章學習ROS機器視覺處理,本文先學習一些外圍的知識,為后面的人臉識別,目標跟蹤和yolov5目標檢測做準備。
我的筆記本是Thinkpad T14 i7 + Nvidia MX450,系統(tǒng)是ubuntu20.04,ros是noetic。由于很多驅動與硬件強相關,請讀者注意這點。
本文的參考資料有:
(1)《ROS機器人開發(fā)實踐》胡春旭 第7章的前三節(jié)
(2)圖像編碼與 H264 基礎知識
(3)ubuntu20.04如何識別到連接的攝像頭?
(4)ROS學習 – 攝像頭的標定
(5)相機內參標定究竟標了什么?相機內參外參保姆級教程
(6)ROS高效入門第一章 – ROS歷史與現狀 2.8節(jié)
(7)W3Cschool - OpenCV教程
(8)ChatGPT4.0(很多背景知識,問他比較快,但是要小心它忽悠你!)
2 正文
2.1 顏色編碼格式,圖像格式和視頻壓縮格式
(1)RGB和BGR:這是兩種常見的顏色編碼格式,分別代表了紅、綠、藍三原色。不同之處在于,RGB按照紅、綠、藍的順序存儲顏色信息,而BGR按照藍、綠、紅的順序存儲。
rgb8圖像格式:常用于顯示系統(tǒng),如電視和計算機屏幕。
RGB值以8 bits表示每種顏色,總共可以表示256×256×256=16777216種顏色。
例如: (255,0,0) 表示紅色,(0,255,0) 表示綠色,(0,0,255) 表示藍色。
bgr8圖像格式:由一些特定的硬件制造商采用,
軟件方面最著名的就是opencv,其默認使用BGR的顏色格式來處理圖像。
與RGB不同, (0,0,255) 在BGR中表示紅色,(0,255,0) 仍然表示綠色,(255,0,0) 表示藍色。
在自動駕駛里,使用rgb8圖像格式的圖像,一般稱為原圖,是數據量最大的格式,沒有任何壓縮。
(2)YUV:這是另一種顏色編碼方法,與RGB模型不同的是,它將圖像信息分解為亮度(Y)和色度(U和V)兩部分。這種方式更接近于人類對顏色的感知方式。
Y:代表亮度信息,也就是灰階值。
U:從色度信號中減去Y得到的藍色信號的差異值。
V:從色度信號中減去Y得到的紅色信號的差異值。
YUV顏色編碼主要用在電視系統(tǒng)以及視頻編解碼標準中,在這些系統(tǒng)中,Y通道信息可以單獨使用,這樣黑白電視機也能接收和顯示信號。而彩色信息則通過U和V兩個通道傳輸,只有彩色電視機才能處理。這樣設計兼容了黑白電視和彩色電視。
YUV色彩空間相比RGB色彩空間,更加符合人眼對亮度和色彩的敏感度,在視頻壓縮時,可以按照人眼的敏感度對YUV數據進行壓縮,以達到更高的壓縮比。
由于歷史和技術的原因,YUV的標準存在多種,例如YUV 4:4:4、YUV 4:2:2和YUV 4:2:0等,這些主要是針對U和V通道的采樣方式不同定義的。采樣不同,對應的壓縮比也不同。
(3)圖像壓縮格式:
jpeg:Joint Photographic Experts Group,是一種常見的用于靜態(tài)圖像的損失性壓縮格式,
它特別適合于全彩色和灰度圖片,被廣泛使用。
通常情況下,JPEG可以提供10:1到20:1的有損壓縮比,根據圖像質量自由調整。
png: Portable Network Graphics,PNG是一種無損壓縮格式,主要使用了DEFLATE算法。
由于這是無損壓縮,所以解壓縮圖像可以完全恢復原始數據。
被廣泛應用于需要高質量圖像的場景,如網頁設計、藝術作品等。
bmp:Bitmap,BMP是Windows系統(tǒng)中常用的一種無壓縮的位圖圖像格式,通常會創(chuàng)造出較大的文件。
位圖(Bitmap)是一種常見的計算機圖形,最小單位是像素,每個像素都包含一定量的信息,如顏色和亮度等。位圖圖像的一個主要特點就是,在放大查看時,可以看到圖像的像素化現象,也就是我們常說的"馬賽克"。BMP、JPEG、GIF、PNG等都是常見的位圖格式。
(4)H264和H265:這是兩個視頻壓縮格式,也是兩種視頻編解碼標準。以1280*720的攝像頭為例,如果是rgb8格式的原圖,一幀圖像的大小是:
如果是一小時的視頻,那將是非常大的數據量,對網絡傳輸,數據存儲,都是很大的壓力。而H264通過種種幀間操作,可以達到10:1到50:1的壓縮比,甚至更高。H265更進一步,壓縮比更高,用來解決4K或8K視頻的傳輸。更具體的原理見:圖像編碼與 H264 基礎知識
在自動駕駛領域,圖像數據也使用h264格式,主要用于數采和回放,控制數據量。
2.2 usb_cam
(1)linux針對攝像頭硬件有一套Video for Linux內核驅動框架,對應提供的有命令行工具 v4l2-ctl (Video for Linux 2),可以查看攝像頭硬件信息:
ls /dev/video0 //一般video0是筆記本自帶攝像頭設備文件
v4l2-ctl -d /dev/video0 --all
這里截取了部分關鍵信息,下面的usb_cam的launch文件將用到:
(2)usb_cam是ros里usb camera的軟件包,一般稱為ros攝像頭驅動,但這是一個應用程序,其調用v4l2并通過ros topic發(fā)出圖像數據。搞機器視覺,第一步就是要有圖。
安裝并啟動usb_cam,查看圖像:
sudo apt-get install ros-noetic-usb-cam
roslaunch usb_cam usb_cam-test.launch
rqt_image_view
usb_cam-test.launch:
<launch>
<node name="usb_cam" pkg="usb_cam" type="usb_cam_node" output="screen" >
//指定設備文件名,默認是/dev/video0
<param name="video_device" value="/dev/video0" />
// 寬和高分辨率
<param name="image_width" value="640" />
<param name="image_height" value="480" />
// 像素編碼,可選值:mjpeg,yuyv,uyvy
<param name="pixel_format" value="yuyv" />
<param name="color_format" value="yuv422p" />
// camera坐標系名
<param name="camera_frame_id" value="usb_cam" />
// IO通道,可選值:mmap,read,userptr,大數據量信息一般用mmap
<param name="io_method" value="mmap"/>
</node>
<node name="image_view" pkg="image_view" type="image_view" respawn="false" output="screen">
// 指定發(fā)出的topic名:/usb_cam/image_raw
<remap from="image" to="/usb_cam/image_raw"/>
<param name="autosize" value="true" />
</node>
</launch>
(3)/usb_cam/image_raw的數據結構體:
rostopic info /usb_cam/image_raw
rosmsg show sensor_msgs/Image
//消息頭,每個topic都有
std_msgs/Header header
uint32 seq
time stamp
// 坐標系名
string frame_id
// 高和寬分辨率
uint32 height
uint32 width
// 無壓縮的圖像編碼格式,包括rgb8,YUV444
string encoding
// 圖像數據的大小端存儲模式
uint8 is_bigendian
// 一行圖像數據的字節(jié)數量,作為步長參數
uint32 step
// 存儲圖像數據的柔性數組,大小是step*height
uint8[] data
/usb_cam/image_raw內容展示:
(4)/usb_cam/image_raw/compressed的數據結構體:
rostopic info /usb_cam/image_raw/compressed
rosmsg show sensor_msgs/CompressedImage
std_msgs/Header header
uint32 seq
time stamp
string frame_id
// 壓縮的圖像編碼格式,jpeg,png
string format
uint8[] data
/usb_cam/image_raw/compressed內容展示:
(5)踩坑記錄
當我拉起來usb_cam時,死活不出圖,顯示框有,但就是黑的,找了半天資料也沒解決。
后來發(fā)現,Thinkpad T14的攝像頭是有個物理開關的,需要手動打開,不然攝像頭就被遮擋了!
2.3 攝像頭標定
2.3.1 標定引入
(1)Calibration:翻譯過來就是校準和標定。
(2)攝像頭標定:Camera Calibration是計算機視覺中的一種關鍵技術,其目的是確定攝像頭的內部參數(Intrinsic Parameters)和外部參數(Extrinsic Parameters)。
內部參數:包括焦距、主點坐標以及鏡頭畸變等因素。
這些參數與相機本身的硬件有關,如鏡頭和圖像傳感器等,一般由廠家提供。
外部參數:攝像頭相對于環(huán)境的位置和方向。
例如,它可能描述了一個固定攝像頭相對于周圍環(huán)境的姿態(tài)或者安裝位置。
以汽車為例,外參包括各個攝像頭之間的關系,攝像頭與radar,攝像頭與lidar的關系。
(3)汽車各種傳感器的之間的相對位置和朝向,用3自由度的旋轉矩陣和3自由度的平移向量表示,這些外參由整車廠自己標。
一般整車下線之后,進入特定的房間,使用靜態(tài)標靶、定位器的等高精度設備,完成Camera、radar、Lidar等傳感器的標定,稱之為產線標定,也叫做下線標定。
2.3.2 筆記本攝像頭內參標定
這里我們使用標定常用的標靶圖形,完成筆記本攝像頭的內參標定。usb_cam可以使用內參標定,避免圖像畸變。
(1)安裝標定功能包(ubuntu20.04+noetic)
sudo apt-get install ros-noetic-camera-calibration
(2)創(chuàng)建 robot_vision 軟件包,并標定相關文件
cd ~/catkin_ws/src
catkin_create_pkg robot_vision cv_bridge image_transport sensor_msgs std_msgs geometry_msgs message_generation roscpp rospy
cd robot_vision
mkdir doc launch
touch launch/cameta_calibration.launch
圖片鏈接:標定靶圖片:
cameta_calibration.launch:
<launch>
// 使用usb_cam包,發(fā)出/usb_cam/image_raw圖像數據
<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>
// 使用標定功能包,完成標定。
// 參數中,8x6表示橫向8個內部角點,豎向有6個
// square 是每個棋盤格的邊長
// /usb_cam/image_raw是監(jiān)聽的圖像topic
<node
pkg="camera_calibration"
type="cameracalibrator.py"
name="camera_calibration"
output="screen"
args="--size 8x6 --square 0.024 image:=/usb_cam/image_raw camera:=/usb_cam"
/>
</launch>
(3)編譯并運行
cd ~/catkin_ws/
catkin_make --source src/robot_vision
source devel/setup.bash
roslaunch robot_vision cameta_calibration.launch
不斷晃動,直到COMMIT按鍵亮起,然后點擊,即可生成標定文件,本人的路徑為:/home/mm/.ros/camera_info/head_camera.yaml。具體的生成原理和文件內容,這里暫不深究,可以參考鏈接:相機內參標定究竟標了什么?相機內參外參保姆級教程
2.4 opencv和cv_bridge引入
(1)opencv和cv_bridge的簡介可以看本人之前的博客:ROS高效入門第一章 – ROS歷史與現狀 2.8節(jié)
安裝opencv(ubuntu20.04+noetic):
sudo apt-get install ros-noetic-vision-opencv libopencv-dev python3-opencv
(2)opencv和cv_bridge的簡單架構圖如下:
根據這個圖,在ros里,處理圖像的流程一般是:
# 第一步:使用cv_bridge將ROS的圖像數據轉換成OpenCV的圖像格式
cv_image = cv_bridge.imgmsg_to_cv2(msg, "bgr8")
# 第二步:使用opencv進行圖像處理
。。。
# 第三步,再將opencv格式額數據轉換成ros image格式的數據
ros_image = cv_bridge.cv2_to_imgmsg(cv_image, "bgr8")
本文不深入講解opencv,推薦一個資料:W3Cschool - OpenCV教程
(3)在 上節(jié)的robot_vision包里,我們新增一個cv_bridge的小樣例,主要功能是在捕捉到的圖像上打個藍色的圓標。
cd ~/catkin_ws/src/robot_vision
mkdir scripts
touch scripts/cv_bridge_test.py launch/cv_bridge_test.launch
cv_bridge_test.py:
#! /usr/bin/env python3
# -*- coding: utf-8 -*-
import rospy
import cv2
from functools import partial
from cv_bridge import CvBridge, CvBridgeError
from sensor_msgs.msg import Image
def image_cb(msg, cv_bridge, image_pub):
# 使用cv_bridge將ROS的圖像數據轉換成OpenCV的圖像格式
try:
cv_image = cv_bridge.imgmsg_to_cv2(msg, "bgr8")
except CvBridgeError as e:
print(e)
# 在opencv的顯示窗口中繪制一個圓,作為標記
# cv_image.shape返回一個元組,包含圖像的行數(高度),列數(寬度)和通道數(通常是3個通道:BGR)
(rows, cols, channels) = cv_image.shape
# 當圖像的寬度和高度都大于60時,才執(zhí)行畫圓標動作
if cols > 60 and rows > 60:
# 在計算機圖像處理中,圖像的原點(0,0)通常定義為圖像的左上角。(60,60)是圓心的坐標。
# 30是圓的半徑。
# (255,0,0)定義了圓的顏色。在OpenCV中,默認的顏色空間是BGR,所以這其實是繪制了一個藍色的圓。
# -1表示填充圓。如果這個值是正數,則代表繪制的圓的線寬;如果是負數,則代表填充該圓。
cv2.circle(cv_image, (60,60), 30, (255,0,0), -1)
# 使用Opencv的接口,顯示Opencv格式的圖像
cv2.imshow("ycao: opencv image window", cv_image)
cv2.waitKey(3)
# 再將opencv格式額數據轉換成ros image格式的數據發(fā)布
try:
image_pub.publish(cv_bridge.cv2_to_imgmsg(cv_image, "bgr8"))
except CvBridgeError as e:
print(e)
def main():
rospy.init_node("cv_bridge_test")
rospy.loginfo("starting cv_bridge_test node")
bridge = CvBridge()
image_pub = rospy.Publisher("/cv_bridge_image", Image, queue_size=1)
bind_image_cb = partial(image_cb, cv_bridge=bridge, image_pub=image_pub)
// 訂閱/usb_cam/image_raw,然后再回調函數里處理圖像,并發(fā)布出來
rospy.Subscriber("/usb_cam/image_raw", Image, bind_image_cb)
rospy.spin()
cv2.destroyAllWindows()
if __name__ == "__main__":
main()
cv_bridge_test.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>
<node
pkg="robot_vision"
type="cv_bridge_test.py"
name="cv_bridge_test"
output="screen"
/>
<node
pkg="rqt_image_view"
type="rqt_image_view"
name="rqt_image_view"
output="screen"
/>
</launch>
(4)編譯并運行
cd ~/catkin_ws/
catkin_make --source src/robot_vision
source devel/setup.bash
roslaunch robot_vision cv_bridge_test.launch
文章來源:http://www.zghlxwxcb.cn/news/detail-758164.html
3 總結
本文主要系統(tǒng)介紹了機器視覺處理的外圍知識,引入了opencv和cv_bridge,后面幾篇文章,我們將用它們繼續(xù)豐富 robot_vision 軟件包。
本文的樣例托管在本人的github上:robot_vision文章來源地址http://www.zghlxwxcb.cn/news/detail-758164.html
到了這里,關于ROS高效進階第四章 -- 機器視覺處理之圖像格式,usb_cam,攝像頭標定,opencv和cv_bridge引入的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!