ros功能包所用opencv版本与ros默认opencv版本不一致情况解决方法
这种情况包含比如:
在ubuntu20.04 ros noetic opencv4的环境下部署opencv3的功能包
在ubuntu20.04 ros foxy opencv4的环境下部署opencv3.4.1的功能包(比如部署ros2的vins-fusion-gpu时)
在ubuntu18.04 ros melodic opencv3.3.1的环境下部署opencv3.4.1的功能包(比如部署vins-fusion-gpu时)
解决的关键是使得功能包所调用的cv_bridge功能包是寻找链接的我们想指定的opencv版本,由于ROS功能包一般都是默认用的装ROS时自动二进制安装的cv_bridge功能包,导致默认情况下,ROS功能包就都是使用的同一个版本的opencv,也就是这个二进制安装的cv_bridge功能包所原本找到并链接的opencv,如果我们有功能包需要使用特定版本的opencv,没法使用ros现在默认链接的opencv,此时功能包编译运行便会出现问题,比如opencv4的环境下想用opencv3的功能包,或者opencv3.3.1的环境下想用只能适配于opencv3.4.1的vinsfusiongpu,解决办法就是自己源码编译安装一个cv_bridge(如果是ROS2注意源码编译安装ROS2版本的cv_bridge),使得此cv_bridge使用我们指定版本的opencv,同时使我们的功能包使用我们源码编译安装的这个cv_bridge,就可以实现功能包找到并编译链接的我们指定版本的opencv了。
这里以在ubuntu20.04 opencv4的环境下部署原本依赖opencv3.3.1的功能包为例
首先源码编译安装opencv3.3.1和opencv_contrib3.3.1,这里假设功能包也需要opencv_contrib。
新建一个文件夹opencv331来专门存放opencv3.3.1和opencv_contrib3.3.1
mkdir opencv331
cd opencv331
然后运行下面命令下载opencv3.3.1和opencv_contrib3.3.1
git clone -b 3.3.1 https://github.com/opencv/opencv.git
git clone -b 3.3.1 https://github.com/opencv/opencv_contrib
接着编译安装
下面camke命令中,CMAKE_INSTALL_PREFIX指定了安装路径,OPENCV_EXTRA_MODULES_PATH指定了opencv_contrib的路径,注意确保opencv_contrib和opencv处于同一个文件夹内,下面OPENCV_EXTRA_MODULES_PATH指定的相对路径才有效。
cd opencv
mkdir build
cd build
cmake -D CMAKE_BUILD_TYPE=Release -D WITH_CUDA=OFF -D CMAKE_INSTALL_PREFIX=/usr/local -D OPENCV_EXTRA_MODULES_PATH=../../opencv_contrib/modules ..
make -j8
sudo make install
此时ubuntu环境里面可以找到opencv4也可以找到opencv3
查找opencv3版本命令可以用
pkg-config --modversion opencv
查找opencv4版本命令可以用
pkg-config --modversion opencv4
此时单纯地把功能包的cmakelists里面的find_package(OpenCV REQUIRED)改为find_package(OpenCV 3.3.1 REQUIRED)是不够的,这样虽然可以找到opencv3.3.1,但是编译链接时会依旧链接的opencv4的库文件,因为ubuntu20.04上ros noetic二进制安装的cv_bridge默认链接的是opencv4,这样编译一般会出现譬如undefined reference to cv::mat::mat()一类带有undefined的报错,出现这种undefined的报错一般是因为找到了头文件,但是链接库的时候没有链接库或者没有找到库导致的,因为头文件一般只有函数的声明,库文件才带有函数的定义实现。
可以cmakelists里面加上这些打印,会发现虽然找到的是opencv3.3.1,但是链接的库还是opencv4的
message(STATUS "OpenCV library status:")
message(STATUS " version: ${OpenCV_VERSION}")
message(STATUS " libraries: ${OpenCV_LIBS}")
message(STATUS " include path: ${OpenCV_INCLUDE_DIRS}")
message(STATUS " catkin libraries: ${catkin_LIBRARIES}")
此时需要自己再另外编码编译安装一个cv_bridge,之前系统二进制安装的cv_bridge不用卸载,只需要保证自己的功能包找到的cv_bridge功能包是源码编译安装的cv_bridge功能包即可。实现这个的操作就是自己功能包的cmakelists里面加上set(cv_bridge_DIR "your-path/cv_bridge_ws/devel/share/cv_bridge/cmake")
。
按照下面操作源码编译部署一个cv_bridge,使得这个cv_bridge是调用的opencv3.3.1,同时自己这个功能包是找到的这个源码编译的cv_bridge,而不是系统二进制安装的cv_bridge就可以了。
ros1下源码编译安装cv_bridge
mkdir -p cv_bridge_ws/src
cd cv_bridge_ws/src
git clone https://gitee.com/maxibooksiyi/cv_bridge
cd ..
将opencv编译生成的build文件路径加入到cv_bridge功能包的CMakeLists.txt里,命令如下,像上面自己编译安装的opecv3.3.1的build文件夹路径就是~/opencv331/opencv/build
set(OpenCV_DIR "your-path/opencv-x.x.x/build")
编译
catkin_make
如果是ros2,则源码编译安装cv_bridge功能包的步骤是
mkdir cv_bridge_ros2_ws/src
cd cv_bridge_ros2_ws
cd src
git clone https://github.com/ros-perception/vision_opencv.git -b foxy
把cv_bridge功能包里的cmakelists(/cv_bridge_ros2_ws/src/vision_opencv/cv_bridge/CMakeLists.txt)里这里的OpenCV 4改为OpenCV 3
改完后保存编译
cd ..
colcon build
源码编译部署完cv_bridge功能包之后,最后将依赖使用指定opencv版本的功能包里的CMakeLists.txt文件按照下面命令添加opencv路径以及cv_bridge路径,位置放在OpenCV和cv_bridge的find_package之前即可,这样再编译这个功能包就会链接的是所指定版本的opencv,而不是原来ros默认链接的opencv了。
set(OpenCV_DIR "your-path/opencv-x.x.x/build")
set(cv_bridge_DIR "your-path/cv_bridge_ws/devel/share/cv_bridge/cmake")