ros kinetic 自带opencv3 与 opencv 2 的兼容问题

问题分析

自己写的系统必须基于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 ""
-- Installing: /usr/local/lib/python2.7/dist-packages/cv_bridge/boost/cv_bridge_boost.so
-- Set runtime path of "/usr/local/lib/python2.7/dist-packages/cv_bridge/boost/cv_bridge_boost.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}

然后按顺序编译,大功告成!!!!

 

其他

1、so文件来源

一开始我检查自己的CMakeLists.txt中,所有 target_link_libraries 的地方都没找到opencv 3.x的引用,后来梳理了ros的性质,

rosbuild_add_executable() 指令会从 manifest.xml 中读取包,而我的manifest.xml中包含了 cv_bridge

而cv_bridge自带的 cmake文件中加载了 3.x的so文件.

2、 关于ros自带包在CMakeLists.txt中的结构

这个过程其实是把 cv_bridge 当成了一个普通的库来使用的。

而ros有一套体系来让这些很简便, 如 catkin components中直接加入 cv_bridge,其实底层和这个过程是一样的。

所以这里弄明白了,ros的底层依赖关系也差不多可以自己diy了。

4、关于删除 cv_bridge 后的影响

这里卸载cv_bridge后发生了ros gazebo不发布话题的问题,其实仔细一想自带的cv_bridge可以留着,然后通过在CMakeLists.txt中指定 cv_bridge_DIR的方式来选择性调用cv_bridge版本。

5、 两个版本的安装路径

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

你可能感兴趣的:(实践经验)