自己写的系统必须基于opencv 2.x,而ros kinetic自带了opencv3的版本。于是在编译时报错:
/usr/bin/ld: CMakeFiles/xxxx.cpp.o: undefined reference to symbol '_ZN2cv6String10deallocateEv'
/opt/ros/kinetic/lib/x86_64-linux-gnu/libopencv_core3.so.3.3.1: error adding symbols: DSO missing from command line
collect2: error: ld returned 1 exit status
CMakeFiles/xxxx/build.make:192: recipe for target '../xxxx' failed
而自己的系统里 Pangolin 等一堆库都基于2.x版本opencv了,不好再做调整,于是只好强行调整ros的opencv依赖来使其适应我的系统了。
ros中用到opencv的地方是从话题中读取图像,如 /camera/image_raw话题中抓取 rgb或depth图像保存为cv::Mat,所需用到的ros包是cv_bridge。
因此核心问题是: ros的包cv_bridge使用默认opencv3编译,而自身系统使用opencv 2.x编译,opencv的混合编译带来了错误。
方法一共有两种:
1) 浅依赖可以直接调整cv_bridge的cmake文件,详细可参考:https://www.mobibrw.com/2017/8718
这个方法可以帮助我通过编译,然而实际运行时会报内存错误。因此放弃选择第二个方式,各位如果想省时间也可以试试这个方式,只需要改文件的几行路径。
注意: 改完cv_bridge的cmake文件后,一定要 rm -rf build 文件然后重新 cmake .. & make 才会生效。
2)重度依赖,一劳永逸
直接将cv_bridge卸载掉,然后从源代码重新编译,详细参考:https://blog.csdn.net/xiat5/article/details/79354573
下面是我的执行过程。
使用opencv 2.x版本重新编译 cv_bridge。
1、 卸载 cv_bridge
使用指令卸载cv_bridge,
$ sudo apt-get remove --purge ros-kinetic-cv-bridge
这里会出现提示说下列包会被一并卸载,不用慌,直接y卸载,实测不影响ros 通信等基本功能的使用 [ 这里有一点提一下,可见文章最后 ]:
ros-kinetic-camera-calibration ros-kinetic-compressed-depth-image-transport
ros-kinetic-compressed-image-transport ros-kinetic-cv-bridge ros-kinetic-depth-image-proc ros-kinetic-desktop
ros-kinetic-desktop-full ros-kinetic-gazebo-plugins ros-kinetic-gazebo-ros-pkgs ros-kinetic-image-pipeline
ros-kinetic-image-proc ros-kinetic-image-publisher ros-kinetic-image-rotate ros-kinetic-image-transport-plugins
ros-kinetic-image-view ros-kinetic-perception ros-kinetic-rgbd-launch ros-kinetic-rqt-common-plugins
ros-kinetic-rqt-image-view ros-kinetic-simulators ros-kinetic-stereo-image-proc
ros-kinetic-theora-image-transport ros-kinetic-vision-opencv ros-kinetic-viz
2、 到github上clone 下来cv_bridge
gihub地址为: https://github.com/ros-perception/vision_opencv
切换kinetic版本:
$ git checkout kinetic
3、 修改CMakeLists.txt文件指定为你自己的opencv版本.
拿我的为例子,我的opencv 2.4.11的build路径为: ~/opencv_2.4.11/build
于是我在 find_package(OpenCV)前加入一行::
set( OpenCV_DIR "~/opencv_2.4.11/build" )
建议可以使用message输出一下opencv version或 opencv_include 目录来确保cmake加载的自己版本的opencv.
3、最后
$ cmake .. && make
$ sudo make install
出现下列情况表示安装成功
... -- Set runtime path of "/usr/local/lib/libcv_bridge.so" to "" |
4、回到自己最初需要用ros的代码里,对CMakeLists.txt中做一些调整:
set(cv_bridge_DIR /usr/local/share/cv_bridge/cmake)
find_package(cv_bridge)
include_directories(${cv_bridge_DIR})
target_link_libraries中将cv_bridge的库文件链接上
${cv_bridge_LIBRARIES}
然后按顺序编译,大功告成!!!!
一开始我检查自己的CMakeLists.txt中,所有 target_link_libraries 的地方都没找到opencv 3.x的引用,后来梳理了ros的性质,
rosbuild_add_executable() 指令会从 manifest.xml 中读取包,而我的manifest.xml中包含了 cv_bridge
而cv_bridge自带的 cmake文件中加载了 3.x的so文件.
这个过程其实是把 cv_bridge 当成了一个普通的库来使用的。
而ros有一套体系来让这些很简便, 如 catkin components中直接加入 cv_bridge,其实底层和这个过程是一样的。
所以这里弄明白了,ros的底层依赖关系也差不多可以自己diy了。
这里卸载cv_bridge后发生了ros gazebo不发布话题的问题,其实仔细一想自带的cv_bridge可以留着,然后通过在CMakeLists.txt中指定 cv_bridge_DIR的方式来选择性调用cv_bridge版本。
opencv 2.4.11 检查安装路径为: /usr/local
ros-kinetic安装了opencv3, 检查安装路径为:
lib: /opt/ros/kinetic/lib/x86_64-linux-gnu
include: /opt/ros/kinetic/include/opencv-3.3.1-dev