本文是针对前面三篇所写内容:
进行的一个结合,来综合运用ros,opencv,qt和yaml-cpp库。
首先用catkin_create_pkg命令新建一个ROS工程,然后CMakeLists.txt文件中,依次包含opencv,qt和yaml-cpp,这个比较容易,前面三篇文章也有说明。
其次是在QtGUI中显示opencv图像,一般是用Label控件。这里涉及到另外一个问题,需将opencv中的图像转换为QImage,QImage支持大部分的图像格式,再用QPixmap显示到控件上。图像编码格式每个库又有每个库自己的标准,因此经常会遇上显示不正常的问题。
比较好的做法是根据图像通道进行判断,关键代码如下:
cv::Mat cvImage;
... //一些图像处理操作
QImage qImg = QImage(cvImage.cols, cvImage.rows, QImage::Format_RGB32);
unsigned char *ptrQImage = qImg.bits();
if (1 == cvImage.channels())
{
for(int row = 0; row < cvImage.rows; row++)
{
unsigned char *ptr=(unsigned char*)(cvImage.data + row * cvImage.step1());
for(int col = 0; col < cvImage.cols; col++)
{
*(ptrQImage) = *(ptr+col);
*(ptrQImage+1) = *(ptr+col);
*(ptrQImage+2) = *(ptr+col);
*(ptrQImage+3) = 0;
ptrQImage += 4;
}
}
}
else if (3 == cvImage.channels())
{
for(int row = 0; row < cvImage.rows; row++)
{
unsigned char *ptr=(unsigned char*)(cvImage.data + row * cvImage.step1());
for(int col = 0; col < cvImage.cols; col++)
{
*(ptrQImage) = *(ptr+col*3);
*(ptrQImage+1) = *(ptr+col*3+1);
*(ptrQImage+2) = *(ptr+col*3+2);
*(ptrQImage+3) = 0;
ptrQImage += 4;
}
}
}
ui->label->setPixmap(QPixmap::fromImage(qImg));
QImage中的format有如下:
QImage::Format_Invalid 图像无效
QImage::Format_Mono 存储使用1位每像素的图像,字节填充最重要位第一
QImage::Format_MonoLSB 存储使用1位每像素的图像,字节填充不显著位第一
QImage::Format_Indexed8 图像存储使用8位指标转化成Colormap
QImage::Format_RGB32 存储使用32位RGB格式的图像(0xffrrggbb)
QImage::Format_ARGB32 存储使用32为ARGB格式的图像(0xaarrggbb)
QImage::Format_ARGB32_Premultiplied 图像存储使用一个自左乘32位ARGB格式
QImage::Format_RGB16 图像存储使用5-6-5 16位RGB格式
QImage::Format_ARGB8565_Premultiplied 图像存储使用一个自左乘24位ARGB格式8-5-6-5
QImage::Format_RGB666 图像存储使用6-6-6 24位RGB格式,未使用的最重要的位总是为零
QImage::Format_ARGB6666_Premultiplied 图像存储使用一个自左乘24位ARGB格式6-6-6-6
QImage::Format_RGB555 图像存储使用16位RGB格式(5-5-5),位置用的最重要的始终为零
QImage::Format_ARGB8555_Premultiplied 图像存储使用一个自左乘24位ARGB格式8-5-5-5
QImage::Format_RGB888 图像存储使用8-8-8 24位RGB格式
QImage::Format_RGB444 图像存储使用16位RGB格式(4-4-4)未使用的位始终为零
QImage::Format_ARGB4444_Premultiplied 图像存储使用一个自左乘16位ARGB格式4-4-4-4
QImage::Format_RGBX8888 图像存储使用32位字节命令RGB(x)格式8-8-8-8
QImage::Format_RGBA8888 存储使用32位字节命令RGBA格式(8-8-8-8)的的图像
QImage::Format_RGBA8888_Premultiplied 图像存储使用一个自左乘32位字节命令RGBA格式8-8-8-8
QImage::Format_BGR30 存储使用32位BGR格式(x-10-10-10)的的图像
QImage::Format_A2BGR30_Premultiplied 图像存储使用32位自左乘abgr格式2-10-10-10
QImage::Format_RGB30 存储使用32位RGB格式(x-10-10-10)的的图像
QImage::Format_A2RGB30_Premultiplied 图像存储使用2-10-10-10 32位自左乘ARGB格式
QImage::Format_Alpha8 该图像是使用一个8位的阿尔法格式存储
QImage::Format_Grayscale8 图像是使用一个8位灰度格式存储
不同Qt版本,这个Format枚举类型还略有点不同,不过常用的基本都包含了。实在不行,可以用opencv库转成常用的8-8-8 24位RGB格式。
关于图像滤波,是很常见和基础的图像处理,opencv中有现成的库可以调用,本示例给出了三种滤波方式(方框滤波,均值滤波和高斯滤波):
该工程具备的基本功能为:打开并选择图像,选择滤波类型,调节滑动条可观察滤波效果。点击Save可将滤波类型和调节的参数。下次再打开图像时,会直接读取该参数并进行滤波。
此外,图像会以为ros topic的形式发布出来,可用rosrun rqt_image_view rqt_image_view查看。
opencv图像转换为ros图像和qt格式的图像代码如下:
cv::Mat matImg;
sensor_msgs::ImagePtr msg;
msg = cv_bridge::CvImage(std_msgs::Header(), "bgr8", matImg).toImageMsg(); //ros中的图像编码格式'bgr8'
m_pub.publish(msg);
cv::Mat showImg;
cv::cvtColor(matImg, showImg, CV_BGR2RGB); //BGR图像转换为RGB格式
m_qImg = QImage((const unsigned char*)(showImg.data), showImg.cols, showImg.rows, QImage::Format_RGB888);
ui->label->setPixmap(QPixmap::fromImage(m_qImg));
工程源码下载地址:
https://github.com/WelinLee/ros_cv_qt_gui
Enjoy!