1前景提要:
-
cv_bridge是ros中常用的消息类型转换的包(ros自带的包),要在ros环境下利用opencv处理USB相机拍摄的视频必须用到cv_bridge(如下图),详见https://blog.csdn.net/Robogreen/article/details/50487382
-
在网上找到相应文章之后(详见https://blog.csdn.net/qq_28306361/article/details/85142192,代码也贴在下面了),将代码copy过来,catkin_make的时候发现有以下错误提示:
#include <ros/ros.h>
#include <stdio.h>
#include <image_transport/image_transport.h>
#include <cv_bridge/cv_bridge.h>
#include <sensor_msgs/image_encodings.h>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
static const char WINDOW[] = "Image window";
static void help()
{
printf("\nThis program demonstrates converting OpenCV Image to ROS Image messages \n"
);
}
int main(int argc, char** argv)
{
help();
ros::init(argc, argv, "image_converter");
//Reading an image from the file
cv::Mat cv_image = cv::imread("/home/vlt/Pictures/1.jpg");
if(cv_image.empty() )
{
ROS_ERROR("Read the picture failed!");
return -1;
}
//Convert OpenCV image to ROS message
ros::NodeHandle node;
image_transport::ImageTransport transport(node);
image_transport::Publisher image_pub;
image_pub=transport.advertise("OutImage", 1);
ros::Time time=ros::Time::now();
cv_bridge::CvImage cvi;
cvi.header.stamp = time;
cvi.header.frame_id = "image";
cvi.encoding = "bgr8";
cvi.image = cv_image;
sensor_msgs::Image im;
cvi.toImageMsg(im);
image_pub.publish(im);
ROS_INFO("Converted Successfully!");
//Show the image
cv::namedWindow(WINDOW);
cv::imshow(WINDOW,cv_image);
cv::waitKey(0);
ros::spin();
return 0;
}
主要是那两个未定义的引用让人头大。因为代码中还有其他cv::imread等opencv库中的函数,为什么唯独错误提示中的那两个函数显示未定义的引用呢?
2解决过程(这个过程可以略去不看,直接看下面的最终解决办法)
- 卸载系统自带的opencv2,重新下载安装并配置opencv2.4.9(见https://blog.csdn.net/weixin_40522162/article/details/79921370)
- 还是一样的报错,然后又在程序的cmakelist中添加了库的链接(见https://blog.csdn.net/qq_37340588/article/details/107057987):
set(OpenCV_DIR /usr/local/opencv2.4.9/share/OpenCV)
find_package(OpenCV 2.4.9 REQUIRED)
include_directories(SYSTEM ${OpenCV_INCLUDE_DIRS} /usr/local/opencv2.4.9/include)
link_directories(${OpenCV_LIBRARY_DIRS} /usr/local/opencv2.4.9/lib))
- 还是一样的报错,这个时候人都傻了啊啊啊啊啊啊啊啊,甚至想卸载重装ros了。明明位置已经指定的明明白白的了,为什么还是未定义呢???
- 然后看到了一篇博客(见https://blog.csdn.net/bigdog_1027/article/details/79092263),终于明白了。原来先前的很多参考博客都没有提到cv_bridge,只是解决了opencv的版本问题。而我用的程序出错的罪魁祸首是cv_bridge这个包,详见3最终解决办法。
3最终解决办法
- 首先我们要明白,如果最开始安装的是完整的ros的话,是会自带opencv包的,ros-kinetic自带的是opencv3.3.1-dev,我们在/opt/ros/kinetic/include/opencv-3.3.1-dev这个路径下可以看到它。
- 但是,ros自带的opencv包是很不完整的,有很多函数都没有,比如我们进入opencv2/highgui查看highgui.hpp头文件(如下图),可以看到里面甚至没有内容
- 最重要的是,cv_bridge的cmake文件(里面写了这个包需要链接的一些库)中默认调用的是ros自带的opencv3.3.1-dev,而且经过之前报错的实践可以知道cv_bridge调用opencv版本优先级是高于我们写的CmakeList文件调用的opencv的。也就是说,只要我们用了cv_bridge,无论在CmakeList中指定的opencv库路径是哪里,它都会默认调用ros自带的opencv3.3.1-dev。而通过上面两点我们知道,ros自带opencv库是不完整的,所以会出现某些函数报“未定义的引用”的错。
- 那么怎么解决这个问题呢?最佳办法就是修改cv_bridge的cmake文件,让它默认调用我们指定的opencv库。修改如下:
1.首先在终端中输入cd /opt/ros/kinetic/share/cv_bridge/cmake
2.然后输入sudo gedit cv_bridgeConfig.cmake
3.然后修改以下两处(图片借鉴于博客https://blog.csdn.net/bigdog_1027/article/details/79092263):
opencv库文件(均为动态库so文件)有很多,在这里我们只是添加了最常用的几种,如果之后有需要还可以再在这个文件中添加。
5.最后保存文件,在CmakeList中添加cv_bridge依赖包,就可以用我们指定的opencv版本啦。
参考链接
1.cv_bridge的原理讲解:https://blog.csdn.net/Robogreen/article/details/50487382
2.cv_bridge的简单应用:https://blog.csdn.net/qq_28306361/article/details/85142192
3.opencv的安装和配置:https://blog.csdn.net/weixin_40522162/article/details/79921370
4.Cmakelist添加opencv库地址:https://blog.csdn.net/qq_37340588/article/details/107057987
5.cv_bridge默认的opencv3和CmakeList中指定的opencv2冲突的问题:https://blog.csdn.net/bigdog_1027/article/details/79092263