[OpenCV] Ubuntu에서 local에 OpenCV를 설치하고 C++에서 사용하는 방법
해당 게시물을 참고하러 오시는 분들이 많으신 것 같습니다.
로컬에서 환경을 조작해 문제를 해결할 수도 있겠지만,
Docker를 이용하여 환경에 구애받지 않고 OpenCV 및 ROS를 사용하시는 것을 권장드립니다.
ROS나 OpenCV도 어려운데 Docker까지 하시려면 부담이 될 수 있겠지만,
앞으로는 Docker Container를 이용한 개발이 필수가 될 것이라 생각되니,
천천히라도 익혀보시길 권장드리겠습니다.
Ubuntu에서 OpenCV를 설치하는 경우, 보통 시스템 폴더 안 (ex. usr/local/include) 에 설치되게 된다.
만약 다른 버전의 OpenCV를 설치하고자 하는 경우 시스템 폴더 안의 OpenCV를 삭제하고 다시 설치하게 되는 경우가 많은데,
이런 경우 제대로 OpenCV 제거 및 설치하기가 쉽지 않다.
또한 프로그램마다 필요로 하는 OpenCV 버전이 다를 수 도 있기 때문에, local 저장공간에 다른 버전의 OpenCV를 설치하고 이를 해당 프로그램에서 사용할 수 있다면 매우 편리할 것이다.
아래 링크를 참조하면 자세한 내용을 확인할 수 있다.
https://www.learnopencv.com/install-opencv-3-4-4-on-ubuntu-16-04/
# Issue
문제가 발생했다. 필자의 개발 환경에는 Ubuntu 16.04 LTS에 ROS Kinetic이 설치되어 있다.
이 때문에 OpenCV를 링크할 때에 ROS에 설치된 OpenCV인 OpenCV 3.3.1-dev 버전으로 적용되는 것이다.
(아무리 다르게 환경설정을 해도)
이를 해결하기 위해 순차적으로 실험을 진행해보겠다.
작업순서는 다음과 같다.
1. opencv version test용 catkin workspace 만들기
$ cd ~
$ mkdir catkin_ws_opencv_version
$ cd catkin_ws_opencv_version
$ mkdir src
$ cd src
$ catkin_init_workspace
$ catkin_create_pkg opencv_version_test roscpp
$ cd opencv_version_test
$ cd ~/catkin_ws_opencv_version
$ catkin build
$ source devel/setup.bash
2. test 용 cpp 파일 만들기
$ cd ~/catkin_ws_opencv_version/src/opencv_version_test/src
$ nano opencv_version_test.cpp
링크를 참조하면 아래와 같은 코드를 통해 OpenCV version을 cpp 프로그램 내에서 확인할 수 있다.
일단 빌드만 해보기 위해 opencv 관련문구는 주석처리를 한다.
또한 ros로 돌려야 하기 때문에 노드 초기화도 해주어야 한다.
#include <ros/ros.h>
#include <iostream>
//#include "opencv2/opencv.hpp"
int main(int argc, char** argv) {
ros::init(argc, argv, "opencv_version_test");
ros::NodeHandle nh;
//std::cout << "OpenCV version : " << CV_VERSION << std::endl;
return 0;
}
3. CMakeLists.txt 수정
이제 CMakeLists.txt를 다음과 같이 수정할 것이다.
cmake_minimum_required(VERSION 2.8.3)
project(opencv_version_test)
## Compile as C++11, supported in ROS Kinetic and newer
# add_compile_options(-std=c++11)
find_package(catkin REQUIRED COMPONENTS roscpp)
catkin_package()
include_directories(${catkin_INCLUDE_DIRS})
add_executable(opencv_version_test src/opencv_version_test.cpp)
target_link_libraries(opencv_version_test ${catkin_LIBRARIES})
기본적인 내용만 남겨두고, opencv_version_test.cpp 파일을 이용해 opencv_version_test 노드를 생성한다.
c++11 컴파일러는 차후에 사용할 가능성이 있기 때문에 주석처리만 하여 남겨주었다.
주의할 사항은 catkin_package 처럼 아무 내용이 없더라도 넣어주어야 에러가 나지 않는다는 것이다.
4. Build 해보기
이제 아래내용으로 빌드를 해보면 잘 되는 것을 확인할 수 있다.
$ cd ~/catkin_ws_opencv_version
$ catkin build
5. CMakeLists.txt 및 opencv_version_test.cpp 수정
이제 CMakeLists.txt와 opencv_version_test.cpp를 수정하여 빌드해보자.
참고로 현재 필자의 OpenCV 설치 상태는 개판이다.
ROS의 opencv-3.3.1-dev도 설치되어 있고, usr/local에도 추가적으로 opencv-4.5.0-pre를 설치했고,
local에도 opencv-3.4.4와 opencv-4.5.0-pre가 설치되어있다.
이러한 상황에서 어떤 opencv를 가장 먼저 load하는지 확인해보자.
CMakeLists.txt
cmake_minimum_required(VERSION 2.8.3)
project(opencv_version_test)
## Compile as C++11, supported in ROS Kinetic and newer
# add_compile_options(-std=c++11)
find_package(catkin REQUIRED COMPONENTS roscpp)
find_package(OpenCV REQUIRED)
catkin_package()
include_directories(${catkin_INCLUDE_DIRS})
add_executable(opencv_version_test src/opencv_version_test.cpp)
target_link_libraries(opencv_version_test ${catkin_LIBRARIES} ${OpenCV_LIBS})
opencv_version_test.cpp
#include <ros/ros.h>
#include <iostream>
#include "opencv2/opencv.hpp"
int main(int argc, char** argv) {
ros::init(argc, argv, "opencv_version_test");
ros::NodeHandle nh;
std::cout << "OpenCV version : " << CV_VERSION << std::endl;
return 0;
}
Build
$ ~/catkin_ws_opencv_version
$ catkin build
Run
// terminal_1
$ roscore
// terminal_2
$ rosrun opencv_version_test opencv_version_test
그러면 다음과 같은 결과를 확인할 수 있다.
eh420@eh420-Strix-GL704GW-GL704GW:~/catkin_ws_opencv_version$ rosrun opencv_version_test opencv_version_test
OpenCV version : 3.3.1-dev
OpenCV 3.3.1-dev은 ROS에 설치되어있는 OpenCV version이며, 디폴트로 ROS의 OpenCV를 load 한다는 것을 알 수 있다.
6. local에 설치된 OpenCV 4 설정
이번엔 local에 있는 OpenCV4가 적용되는지 확인해보겠다.
참조한 링크는 다음과 같다.
Install OpenCV 4 on Ubuntu 16.04 (C++ and Python)
CMakeLists.txt
cmake_minimum_required(VERSION 3.1)
project(opencv_version_test)
## Compile as C++11, supported in ROS Kinetic and newer
# add_compile_options(-std=c++11)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED TRUE)
set(OpenCV_DIR /home/eh420/installation/OpenCV-master/lib/cmake/opencv4)
find_package(catkin REQUIRED COMPONENTS roscpp)
find_package(OpenCV REQUIRED)
catkin_package()
include_directories(${catkin_INCLUDE_DIRS})
add_executable(opencv_version_test src/opencv_version_test.cpp)
target_link_libraries(opencv_version_test ${catkin_LIBRARIES} ${OpenCV_LIBS})
Build
$ ~/catkin_ws_opencv_version
$ catkin build
Run
// terminal_1
$ roscore
// terminal_2
$ rosrun opencv_version_test opencv_version_test
그러면 다음과 같은 결과를 확인할 수 있다.
eh420@eh420-Strix-GL704GW-GL704GW:~/catkin_ws_opencv_version$ rosrun opencv_version_test opencv_version_test
OpenCV version : 4.5.0-pre
OpenCV 4.5.0-pre 가 제대로 불러와진 것이다.
7. cv_bridge를 사용하는 경우
cv_bridge는 OpenCV의 이미지 데이터 포맷과 ROS Image 데이터 포맷간의 변환을 위한 패키지이다.
문제는 cv_bridge는 기본적으로 ROS에 설치되어 있는 OpenCV version을 이용한다는 것이다.
이 문제 때문에 cv_bridge와 local에 설치한 OpenCV를 함께 사용하기는 매우 어렵다.
해당 문제에 관한 내용은 다음 링크를 참조한다.
해당 문제를 확인하기 위해 다음과 같이 파일들을 수정하여 실행해보자.
package.xml
<?xml version="1.0"?>
<package format="2">
<name>opencv_version_test</name>
<version>0.0.0</version>
<description>The opencv_version_test package</description>
<maintainer email="eh420@todo.todo">eh420</maintainer>
<license>TODO</license>
<buildtool_depend>catkin</buildtool_depend>
<build_depend>roscpp</build_depend>
<build_depend>cv_bridge</build_depend>
<exec_depend>roscpp</exec_depend>
<exec_depend>cv_bridge</exec_depend>
<export>
</export>
</package>
CMakeLists.txt
cmake_minimum_required(VERSION 3.1)
project(opencv_version_test)
## Compile as C++11, supported in ROS Kinetic and newer
# add_compile_options(-std=c++11)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED TRUE)
set(OpenCV_DIR /usr/local/lib/cmake/opencv4)
find_package(catkin REQUIRED COMPONENTS roscpp cv_bridge)
find_package(OpenCV REQUIRED)
catkin_package(
CATKIN_DEPENDS
roscpp
cv_bridge
)
include_directories(${catkin_INCLUDE_DIRS})
add_executable(opencv_version_test src/opencv_version_test.cpp)
target_link_libraries(opencv_version_test ${catkin_LIBRARIES} ${OpenCV_LIBS})
Build
$ ~/catkin_ws_opencv_version
$ catkin build
Run
// terminal_1
$ roscore
// terminal_2
$ rosrun opencv_version_test opencv_version_test
그러면 다음과 같은 결과를 확인할 수 있다.
eh420@eh420-Strix-GL704GW-GL704GW:~/catkin_ws_opencv_version$ rosrun opencv_version_test opencv_version_test
OpenCV version : 3.3.1-dev
OpenCV 4.5.0-pre 를 무시하고 cv_bridge에서 사용하는 OpenCV 3.3.1-dev 가 불러와진 것이다.
그렇기 때문에 위의 블로그를 참조하여 수정해주는 작업이 필요하다.
8. cv_bridge 수정
먼저 아래 명령어를 통해 cv_bridge config 파일을 켠다.
$ cd /opt/ros/kinetic/share/cv_bridge/cmake/
$ sudo gedit cv_bridgeConfig.cmake
이 후에 다음 구문들을 수정해준다. 이 때, 본인의 OpenCV 경로에 맞추어주면 된다.
cv_bridgeConfig.cmake
include 부분에 자신이 설치한 opencv의 경로를 입력한다.
# default include setting
#if(NOT "include;/opt/ros/kinetic/include/opencv-3.3.1-dev;/opt/ros/kinetic/include/opencv-3.3.1-dev/opencv " STREQUAL " ")
# set(cv_bridge_INCLUDE_DIRS "")
# set(_include_dirs "include;/opt/ros/kinetic/include/opencv-3.3.1-dev;/opt/ros/kinetic/include/opencv-3.3.1-dev/opencv")
# OpenCV 4.5.0-pre include setting
if(NOT "include;/usr/local/include/opencv4/opencv2;/usr/local/include/opencv4; " STREQUAL " ")
set(cv_bridge_INCLUDE_DIRS "")
set(_include_dirs "include;/usr/local/include/opencv4/opencv2;/usr/local/include/opencv4;")
cv_bridgeConfig.cmake
libraries 부분에는 자신이 사용할 라이브러리를 추가해준다.
# default libraries setting
#set(libraries "cv_bridge;/opt/ros/kinetic/lib/x86_64-linux-gnu/libopencv_core3.so.3.3.1;/opt/ros/kinetic/lib/x86_64-linux-gnu/libopencv_imgproc3.so.3.3.1;/opt/ros/kinetic/lib/x86_64-linux-gnu/libopencv_imgcodecs3.so.3.3.1")
# OpenCV 4.5.0-pre libraries setting
set(libraries "cv_bridge;/usr/local/lib/libopencv_core.so.4.5.0;/usr/local/lib/libopencv_imgproc.so.4.5.0;/usr/local/lib/libopencv_imgcodecs.so.4.5.0;/usr/local/lib/libopencv_highgui.so.4.5.0;/usr/local/lib/libopencv_features2d.so.4.5.0;/usr/local/lib/libopencv_xfeatures2d.so.4.5.0;/usr/local/lib/libopencv_stitching.so.4.5.0;")
CMakeLists.txt
이 부분에서 중요한 점은 cv_bridge 만을 활성화 시키고 나머지 OpenCV 관련 내용은 비활성화 시키는 것이다.
이미 cv_bridge에서 내가 필요한 내용은 모두 가져오기 때문에, 다른 작업을 할 필요가 없는 것이다.
cmake_minimum_required(VERSION 3.1)
project(opencv_version_test)
## Compile as C++11, supported in ROS Kinetic and newer
# add_compile_options(-std=c++11)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED TRUE)
#set(OpenCV_DIR /usr/local/lib/cmake/opencv4)
find_package(catkin REQUIRED COMPONENTS roscpp cv_bridge)
#find_package(OpenCV REQUIRED)
catkin_package(
CATKIN_DEPENDS
roscpp
cv_bridge
)
include_directories(${catkin_INCLUDE_DIRS})
add_executable(opencv_version_test src/opencv_version_test.cpp)
#target_link_libraries(opencv_version_test ${catkin_LIBRARIES} ${OpenCV_LIBS})
target_link_libraries(opencv_version_test ${catkin_LIBRARIES})
Build
$ ~/catkin_ws_opencv_version
$ catkin build
Run
// terminal_1
$ roscore
// terminal_2
$ rosrun opencv_version_test opencv_version_test
그러면 다음과 같은 결과를 확인할 수 있다.
eh420@eh420-Strix-GL704GW-GL704GW:~/catkin_ws_opencv_version$ rosrun opencv_version_test opencv_version_test
OpenCV version : 4.5.0-pre
9. custom library와 사용하는 경우?
보통 OpenCV를 사용하는 custom library의 경우 CMakeLists.txt에서 다음과 같이 명시하게 된다.
add_library(custom_lib src/custom_library.cpp )
target_link_libraries(custom_lib ${OpenCV_LIBRARIES})
하지만 cv_bridge를 통해 이미 OpenCV 라이브러리가 빌드 되었으므로, 아래 구문으로 만들면 된다.
add_library(custom_lib src/custom_library.cpp )
target_link_libraries(custom_lib ${catkin_LIBRARIES})