1. 简介
CV是ComputerVision(计算机视觉)缩写,指用摄影机和电脑代替人眼对目标进行识别、跟踪和测量等机器视觉,并进一步做图形处理,使电脑处理成为更适合人眼观察或传送给仪器检测的图像。
2. OpenCV
提到CV必然离不开OpenCV库,OpenCV是一个基于Apache2.0许可(开源)发行的跨平台计算机视觉和机器学习软件库,可以运行在Linux、Windows、Android和Mac OS操作系统上。 它轻量级而且高效——由一系列 C 函数和少量 C++ 类构成,同时提供了Python、Ruby、MATLAB等语言的接口,实现了图像处理和计算机视觉方面的很多通用算法。
以下使用Python3环境展示OpenCV具体使用方法:
2.1. 安装
pip3 install python-opencv
2.2.导入
import cv2
2.3. 常用函数
2.3.1. imread
cv2.imread()为 opencv-python 包的读取图片的函数。
image = cv2.imread(filepath,cv2.IMREAD_COLOR)
cv2.imread()有两个参数,第一个参数filename是图片路径,第二个参数flag表示图片读取模式,共有三种:
cv2.IMREAD_COLOR:加载彩色图片,这个是默认参数,可以直接写1。
cv2.IMREAD_GRAYSCALE:以灰度模式加载图片,可以直接写0。
cv2.IMREAD_UNCHANGED:以图片的原来的格式打开,包括alpha(包括透明度通道),可以直接写-1
读取到的image以多维数组的形式保存图片信息(Mat),前两维表示图片的像素坐标,最后一维表示图片的通道索引,具体图像的通道数由图片的格式来决定
由于OpenCV的早期开发者习惯于使用BGR顺序的颜色模型,因此使用OpenCV中使用的函数,如imread()读到的每个像素的排列是按BGR,而不是常见的RGB
2.3.2. cvtColor
cv2.cvtColor()用于将图像从一个颜色空间转换到另一个颜色空间的转换(目前常见的颜色空间均支持),并且在转换的过程中能够保证数据的类型不变,即转换后的图像的数据类型和位深与源图像一致。
image = cv2.cvtColor(Mat src, Mat dst, int code)
cv::cvtColor()支持多种颜色空间之间的转换,其支持的转换类型和转换码如下:
1、RGB和BGR(opencv默认的彩色图像的颜色空间是BGR)颜色空间的转换 cv::COLOR_BGR2RGB
2、向RGB和BGR图像中增添alpha通道 cv::COLOR_RGB2RGBA
3、从RGB和BGR图像中去除alpha通道 cv::COLOR_RGBA2RGB
4、从RBG和BGR颜色空间转换到灰度空间 cv::COLOR_RGB2GRAY
5、从灰度空间转换到RGB和BGR颜色空间 cv::COLOR_GRAY2RGB
6、RGB和BGR颜色空间与BGR565颜色空间之间的转换 cv::COLOR_RGB2BGR565
7、灰度空间域BGR565之间的转换 cv::COLOR_GRAY2BGR565
8、RGB和BGR颜色空间与CIE XYZ之间的转换 cv::COLOR_RGB2XYZ
9、RGB和BGR颜色空间与uma色度(YCrCb空间)之间的转换 cv::COLOR_RGB2YCrCb
10、RGB和BGR颜色空间与HSV颜色空间之间的相互转换 cv::COLOR_RGB2HSV
11、RGB和BGR颜色空间与HLS颜色空间之间的相互转换 cv::COLOR_RGB2HLS
12、RGB和BGR颜色空间与CIE Lab颜色空间之间的相互转换 cv::COLOR_RGB2Lab
13、RGB和BGR颜色空间与CIE Luv颜色空间之间的相互转换 cv::COLOR_RGB2Luv
14、Bayer格式(raw data)向RGB或BGR颜色空间的转换 cv::COLOR_BayerBG2RGB
2.3.3. resize
cv2.resize()是opencv库中的一个函数,主要起到对图片进行缩放的作用。
image = resize(src, dsize, dst=None, fx=None, fy=None, interpolation=None)
InputArray src :输入,原图像,即待改变大小的图像;
dsize:输出图像的大小,方式为(宽,高)
fx:width方向的缩放比例
fy:height方向的缩放比例
interpolation(插值):这个是指定插值的方式,图像缩放之后,肯定像素要进行重新计算的,就靠这个参数来指定重新计算像素的方式,有以下几种:
INTER_NEAREST - 最邻近插值
INTER_LINEAR - 双线性插值,如果最后一个参数不指定,默认使用这种方法
INTER_CUBIC - 4x4像素邻域内的双立方插值
INTER_LANCZOS4 - 8x8像素邻域内的Lanczos插值
3. 使用CvBridge进行ROS工程移植
实际ROS工程中是以其自己的sensor_msgs/Image消息格式发布图像,考虑到OpenCV便利性,我们希望将ROS与OpenCV结合使用。 CvBridge是一个ROS库,提供ROS和OpenCV之间的接口。 可以在vision_opencv堆栈的cv_bridge软件包中找到CvBridge
3.1. 安装
ROS自带的python版本是2.7, 系统中的cv_bridge也是用python2编译的,如果在python3环境中使用cv_bridge则会报错,需要重新安装
1)安装依赖包
sudo apt-get install ros-melodic-cv-bridge python-catkin-tools python3-dev python3-catkin-pkg-modules python3-numpy python3-yaml
2)创建一个工作空间单独编译cv_bridge功能包
mkdir -p ./cv_bridge_catkin/src
3)进入src目录,下载cv_bridge功能包
cd ./cv_bridge_catkin/src
git clone -b melodic https://github.com/ros-perception/vision_opencv.git
4)使用catkin_make编译,并配置python版本为python3
cd ..
catkin_make -DCMAKE_BUILD_TYPE=Release -DPYTHON_EXECUTABLE=/usr/bin/python3 -DPYTHON_INCLUDE_DIR=/usr/include/python3.6m -DPYTHON_LIBRARY=/usr/lib/x86_64-linux-gnu/libpython3.6m.so
3.2.导入
运行前要执行以下命令,表示将cv_bridge的扩展环境添加到当前虚拟环境中:
source devel/setup.bash --extend
Python代码中导入使用:
from cv_bridge import CvBridge, CvBridgeError
bridge = CvBridge()
3.3. 将ROS图像消息转换为OpenCV图像
要将ROS图像Image消息转换为Mat,模块cv_bridge.CvBridge提供以下功能:
cv_image = bridge.imgmsg_to_cv2(image_message, "passthrough")
可选编码,如果给出默认值“passthrough”,则目标图像编码将与图像消息编码相同。 图像编码可以是以下任何一种OpenCV图像编码:
8UC[1-4]
8SC[1-4]
16UC[1-4]
16SC[1-4]
32SC[1-4]
32FC[1-4]
64FC[1-4]
对于流行的图像编码,CvBridge将根据需要选择进行颜色或像素深度转换。 要使用此功能,请指定编码为以下字符串之一:
mono8: CV_8UC1, grayscale image
mono16: CV_16UC1, 16-bit grayscale image
bgr8: CV_8UC3, color image with blue-green-red color order
rgb8: CV_8UC3, color image with red-green-blue color order
bgra8: CV_8UC4, BGR color image with an alpha channel
rgba8: CV_8UC4, RGB color image with an alpha channel
3.4. 将OpenCV图像转换为ROS图像消息
将OpenCV中Mat转换为ROS中Image图像消息,CvBridge提供以下功能:
image_message = cv2_to_imgmsg(cv_image, "passthrough")
可选编码同上,注意这里编码不会执行任何转换,而是说明cv_image格式,比如编码为“bgr8”,在转换后ROS中Image图像消息仍是正常rgb显示的
3.5. 代码示例
#!/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)
#图像刚从摄像机订阅过来,图像格式是ROS的信息格式。这是还无法使用opencv处理
def callback(self,data):
# 使用cv_bridge的imgmsg_to_cv2将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节点发送发出去
#因此,需要再使用cv2_to_imgmsg将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()