多个ROS包使用不同Opencv版本冲突解决

多个ROS包使用不同Opencv版本冲突一般发生在opencv3和opencv4之间,一劳永逸的解决就是修改代码将3升级到4。

本文提供的方式是不修改代码,隔离opencv环境,使多个opencv版本共存,且被不同ros包编译使用时隔离。

1 源码编译opencv且install到本地。

mkdir -p /home/lucky/Lib/opencv3.4
mv opencv_contrib-3.4.5.tar.gz /home/lucky/Lib/opencv3.4
mv opencv-3.4.5.tar.gz /home/lucky/Lib/opencv3.4
cd /home/lucky/Lib/opencv3.4
tar -xvf opencv_contrib-3.4.5.tar.gz 
tar -xvf opencv-3.4.5.tar.gz 
mv opencv-3.4.5 opencv
mv opencv_contrib-3.4.5 opencv_contrib
cd opencv
mkdir build && cd build
cmake -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=../../opencv/install -D CMAKE_BUILD_TYPE=RELEASE  -D WITH_OPENGL=ON  -D OPENCV_EXTRA_MODULES_PATH=../../opencv_contrib/modules ..
make -j8
make install

注意:CMAKE_INSTALL_PREFIX=../../opencv/install 已经被指定为/home/lucky/opencv3.4/opencv/install目录。因此make install不会安装到系统/usr 目录中,也不需要sudo

2 cv_bridge带来的冲突

我们通常apt安装ros时,会安装了ros-noetic-cv-bridge,这个包被rviz等使用。注意ros-noetic-cv-bridge通常会依赖系统提供的libopencv-dev==4.2,以ubuntu20为例,系统会有一套依赖库:

ros-noetic-desktop -> ros-noetic-cv-bridge -> opencv4.2

假如你的ros包依赖cv-bridge同时依赖opencv3.4,如果你使用ros提供的ros-noetic-cv-bridge(opencv4.2)和自己编译的opencv3.4,那么程序中会有两种libopencv,程序运行时会崩溃,有时候不崩溃但是程序卡住或者数据出错。

例如:

lucky@lucky:~/ws_vins/devel/lib$ ldd feature_tracker/feature_tracker | grep libopencv_core
        libopencv_core.so.4.2 => /home/lucky/Lib/opencv4.2/opencv/install/lib/libopencv_core.so.4.2 (0x00007f774bbeb000) 
        libopencv_core.so.3.4 => /home/lucky/Lib/opencv3.4/opencv/install/lib/libopencv_core.so.3.4 (0x00007f520686c000) 

解决:使用自己本地install的opencv3.4 编译cv_bridge并把编译好的cv_bridge 安装在本地

mkdir -p ~/Lib
下载 https://github.com/ros-perception/vision_opencv/archive/refs/tags/1.13.1.zip
mv vision_opencv-1.13.1.zip ~/Lib
unzip vision_opencv-1.13.1.zip
cd ~/Lib/vision_opencv-1.13.1/cv_bridge
gedit CMakeLists.txt 替换成如下
```
cmake_minimum_required(VERSION 3.0.2)
project(cv_bridge)

find_package(catkin REQUIRED COMPONENTS rosconsole sensor_msgs)

if(NOT ANDROID)
  find_package(PythonLibs)

  if(PYTHONLIBS_VERSION_STRING VERSION_LESS "3.8")
    # Debian Buster
    find_package(Boost REQUIRED python37)
  else()
    # Ubuntu Focal
    find_package(Boost REQUIRED python)
  endif()
else()
find_package(Boost REQUIRED)
endif()

set(OpenCV_DIR "/home/lucky/Lib/opencv3.4/opencv/install/share/OpenCV")
# set(OpenCV_DIR "/home/lucky/Lib/opencv4.5/opencv/install/lib/cmake/opencv4/")
find_package(OpenCV 3.4.5 REQUIRED
  COMPONENTS
    opencv_core
    opencv_imgproc
    opencv_imgcodecs
  CONFIG
)

catkin_package(
  INCLUDE_DIRS include
  LIBRARIES ${PROJECT_NAME}
  CATKIN_DEPENDS rosconsole sensor_msgs
  DEPENDS OpenCV
  CFG_EXTRAS cv_bridge-extras.cmake
)

catkin_python_setup()

include_directories(include ${Boost_INCLUDE_DIRS} ${OpenCV_INCLUDE_DIRS} ${catkin_INCLUDE_DIRS})
link_directories(${Boost_LIBRARY_DIRS})

if(NOT ANDROID)
add_subdirectory(python)
endif()
add_subdirectory(src)
if(CATKIN_ENABLE_TESTING)
  add_subdirectory(test)
endif()

# install the include folder
install(
  DIRECTORY include/${PROJECT_NAME}/
  DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION}
)

# Create uninstall target
configure_file(
    "${CMAKE_CURRENT_SOURCE_DIR}/cmake/uninstall.cmake.in"
    "${CMAKE_CURRENT_BINARY_DIR}/uninstall.cmake"
    IMMEDIATE @ONLY
)

add_custom_target(uninstall
    COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/uninstall.cmake
)
```

gedit cmake/uninstall.cmake.in 拷贝如下内容:(可选,支持uninstall)
```
if(NOT EXISTS "${CMAKE_BINARY_DIR}/install_manifest.txt")
    message(FATAL_ERROR "Cannot find install manifest: ${CMAKE_BINARY_DIR}/install_manifest.txt")
endif()

file(READ "${CMAKE_BINARY_DIR}/install_manifest.txt" files)
string(REGEX REPLACE "\n" ";" files "${files}")

foreach(file ${files})
    message(STATUS "Uninstalling file: ${file}")
    if(EXISTS "${file}")
        execute_process(
            COMMAND ${CMAKE_COMMAND} -E remove "${file}"
            RESULT_VARIABLE result
        )
        if(NOT ${result} EQUAL 0)
            message(FATAL_ERROR "Failed to uninstall: ${file}")
        endif()
    else()
        message(WARNING "File not found: ${file}")
    endif()
endforeach()
```

mkdir build_with_cv3.4
cd build_with_cv3.4
cmake -DCMAKE_INSTALL_PREFIX=../install_with_cv3.4 ..
make -j8
export LD_LIBRARY_PATH=/home/lucky/Lib/opencv3.4/opencv/install/lib:$LD_LIBRARY_PATH; make install

注意: -DCMAKE_INSTALL_PREFIX=/home/lucky/Lib/vision_opencv-1.13.1/cv_bridge/install,指定为本地安装目录;

opencv3和4的cmake配置文件的DIR不同:set(OpenCV_DIR "/home/lucky/Lib/opencv3.4/opencv/install/share/OpenCV")与set(OpenCV_DIR "/home/lucky/Lib/opencv4.5/opencv/install/lib/cmake/opencv4/")

3 ros包中CMakeLists.txt的修改

以vins_mono中的feature_tracker程序为例,修改~/ws_vins/src/VINS-Mono/feature_tracker/CMakeLists.txt

3.1 opencv的指定

**********
find_package(OpenCV REQUIRED)
**********
改为
**********
set(OpenCV_DIR "/home/lucky/Lib/opencv3.4/opencv/install/share/OpenCV")
find_package(OpenCV 3.4.5 REQUIRED)
**********

3.2 cv_bridge的指定 

**********
find_package(catkin REQUIRED COMPONENTS
    roscpp
    std_msgs
    sensor_msgs
    camera_model
    cv_bridge
    )

**********
删除ros中的cv_bridge的依赖,改为:
**********
find_package(catkin REQUIRED COMPONENTS
    roscpp
    std_msgs
    sensor_msgs
    camera_model
    )
**********

指定源码编译的cv_bridge:
**********
set(cv_bridge_DIR "/home/lucky/Lib/vision_opencv-1.13.1/cv_bridge/install_with_cv3.4/share/cv_bridge/cmake")
find_package(cv_bridge 1.13.1 REQUIRED NO_DEFAULT_PATH)
set(OpenCV_DIR "/home/lucky/Lib/opencv3.4/opencv/install/share/OpenCV")
find_package(OpenCV 3.4.5 REQUIRED NO_DEFAULT_PATH)
**********

有时候CMakeLists,按上面修改后虽然可以找到/home/lucky/Lib/vision_opencv-1.13.1/cv_bridge/install/lib/libcv_bridge.so,但总是优先使用了/opt/ros/noetic/lib/libcv_bridge.so,可能跟系统环境有关,可以find_package(cv_bridge 1.13.1 REQUIRED NO_DEFAULT_PATH)

3.3 target_link_libraries指定

**********
target_link_libraries(feature_tracker ${catkin_LIBRARIES} ${OpenCV_LIBS})
**********
改为:
**********
target_link_libraries(feature_tracker ${cv_bridge_LIBRARIES} ${catkin_LIBRARIES} ${OpenCV_LIBS})
**********

3.4 catkin_make

export LD_LIBRARY_PATH=/home/lucky/Lib/opencv3.4/opencv/install/lib:$LD_LIBRARY_PATH
export LD_LIBRARY_PATH=/home/lucky/Lib/vision_opencv-1.13.1/cv_bridge/install/lib:$LD_LIBRARY_PATH
catkin_make

LD_LIBRARY_PATH 中有多个版本的opencv和cv_bridge可能影响其他程序,通过版本号和屏蔽默认(NO_DEFAULT_PATH)的版本两种方式是否生效取决于cv_bridgeConfig.cmake文件是否严格检查。最好不要把export LD_LIBRARY_PATH写入bashrc

4 总结

编译不同版本opencv在本地目录,可以做到多种opencv版本隔离,该方法不需要卸载系统安装的 ros-noetic-cv-bridge -> opencv4.2,不影响rviz或其他ros程序等依赖cv_bridge的使用。

注意:

1 -DCMAKE_INSTALL_PREFIX目录指定为本地

2 不要忽略ros安装的cv_bridge对程序的影响,通常系统安装的cv_bridge依赖的opencv会和程序中依赖的opencv版本不同。

3 自己的ros程序只需要修改CMakeLists.txt,不需要修改源码,本文以vins中的feature_tracker为例,别忘记vins中的其他节点程序的CMakeLists.txt也要修改。

4 多多使用ldd 检查编译后的程序的依赖关系。比如:

  • ldd ~/Lib/vision_opencv-noetic/cv_bridge/install/lib/libcv_bridge.so  | grep cv 的结果中不可以有libopencv_core.so.4.2或其他版本或者not found
  • ldd ~/ws_vins/devel/lib/feature_tracker/feature_tracker | grep cv 的结果中不可以有libopencv_core.so.4.2或其他版本或者not found,也不可以libcv_bridge.so => /opt/ros/noetic/lib/libcv_bridge.so,要指定为libcv_bridge.so => /home/lucky/Lib/vision_opencv-1.13.1/cv_bridge/install/lib/libcv_bridge.so
  • 15
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
ROS使用OpenCV库实现人脸识别,可以按照以下步骤进行: 1. 安装OpenCV库 在Ubuntu 18.04下,可以使用以下命令安装OpenCV库: ``` sudo apt-get install libopencv-dev ``` 2. 创建ROS 使用以下命令创建ROS: ``` catkin_create_pkg face_recognition roscpp rospy std_msgs sensor_msgs cv_bridge image_transport ``` 3. 创建ROS节点 在ROS中创建一个名为`face_recognition_node.cpp`的ROS节点,并在其中实现人脸识别算法。 首先,需要含以下头文件: ```cpp #include <ros/ros.h> #include <sensor_msgs/Image.h> #include <cv_bridge/cv_bridge.h> #include <opencv2/opencv.hpp> ``` 然后,定义ROS节点类,并在类中添加订阅器和回调函数,用于接收图像消息和进行人脸识别: ```cpp class FaceRecognitionNode { public: FaceRecognitionNode() { image_sub_ = nh_.subscribe("/camera/rgb/image_raw", 1, &FaceRecognitionNode::imageCallback, this); } void imageCallback(const sensor_msgs::Image::ConstPtr& msg) { cv_bridge::CvImagePtr cv_ptr; try { cv_ptr = cv_bridge::toCvCopy(msg, sensor_msgs::image_encodings::BGR8); } catch (cv_bridge::Exception& e) { ROS_ERROR("cv_bridge exception: %s", e.what()); return; } // 人脸识别算法 cv::CascadeClassifier face_cascade; face_cascade.load("/usr/share/opencv/haarcascades/haarcascade_frontalface_alt.xml"); std::vector<cv::Rect> faces; cv::Mat gray; cv::cvtColor(cv_ptr->image, gray, cv::COLOR_BGR2GRAY); cv::equalizeHist(gray, gray); face_cascade.detectMultiScale(gray, faces, 1.1, 2, 0 | cv::CASCADE_SCALE_IMAGE, cv::Size(30, 30)); // 在图像中绘制人脸框 for (size_t i = 0; i < faces.size(); i++) { cv::rectangle(cv_ptr->image, faces[i], cv::Scalar(0, 255, 0), 2); } // 发布识别结果 image_pub_.publish(cv_ptr->toImageMsg()); } private: ros::NodeHandle nh_; ros::Subscriber image_sub_; ros::Publisher image_pub_; }; ``` 在回调函数中,将ROS图像消息转换为OpenCV图像格式,并使用OpenCV的人脸识别算法`CascadeClassifier`进行人脸检测。检测到人脸后,在图像中绘制人脸框,并将识别结果发布为ROS图像消息。 4. 编译ROS节点 使用以下命令编译ROS节点: ``` cd ~/catkin_ws catkin_make ``` 5. 运行ROS节点 在终端中运行以下命令启动ROS节点: ``` rosrun face_recognition face_recognition_node ``` 接着,使用以下命令启动相机节点,向ROS节点发送图像消息: ``` roslaunch usb_cam usb_cam-test.launch ``` 最后,可以使用以下命令查看ROS节点发布的人脸识别结果: ``` rosrun image_view image_view image:=/face_recognition/image_raw ``` 这样就可以在ROS中实现基于OpenCV的人脸识别功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值