由于项目需要,这段时间要进行 opencv+cpp 的开发。对比 python 开发中利用 Anaconda 维护不同的开发环境,并用 conda 或 pip 管理各个环境中的包和依赖项1,c++的项目就要复杂的多了。在 python 要安装 opencv-python 只是一行命令的事 pip install opencv-python
,换到 cpp+vs 下就是各种折腾,首先编译 OpenCV 库(可以参考官网教程),然后就是最麻烦的步骤:用 cmake 构建工程。说麻烦,主要是对 cmake 命令不熟悉,不知道如何编写 CMakeLists.txt,同时在网上收集到的不少资料提供的解决办法都很具体,换一个方式可能就又出问题了。忙乎了几天,终于找到了几个教程资料234,现在要做的就是抓紧时间学一学。
准备1:编译完 OpenCV 后找到 OpenCVConfig.cmake
所在路径,我的系统中的路径为 C:\OpenCV\opencv\build\x64\vc15\lib
准备2:一个 OpenCV 相机抓取示例程序video_capture.cpp
(源码为官方示例,名称自己命名的),可以到官网下载
#include
#include
#include
#include
#include
using namespace cv;
using namespace std;
int main(int, char**)
{
Mat frame;
//--- INITIALIZE VIDEOCAPTURE
VideoCapture cap;
// open the default camera using default API
// cap.open(0);
// OR advance usage: select any API backend
int deviceID = 0; // 0 = open default camera
int apiID = cv::CAP_ANY; // 0 = autodetect default API
// open selected camera using selected API
cap.open(deviceID + apiID);
// check if we succeeded
if (!cap.isOpened()) {
cerr << "ERROR! Unable to open camera\n";
return -1;
}
//--- GRAB AND WRITE LOOP
cout << "Start grabbing" << endl
<< "Press any key to terminate" << endl;
for (;;)
{
// wait for a new frame from camera and store it into 'frame'
cap.read(frame);
// check if we succeeded
if (frame.empty()) {
cerr << "ERROR! blank frame grabbed\n";
break;
}
// show live and wait for a key with timeout long enough to show images
imshow("Live", frame);
if (waitKey(5) >= 0)
break;
}
// the camera will be deinitialized automatically in VideoCapture destructor
return 0;
}
project 1 项目的树状结构如图,其包含在info.txt
文件中,是在命令行中使用tree /f > info.txt
生成的5。
D:.
│ CMakeLists.txt
│ info.txt
│ video_capture.cpp
│
└─build
CMakeLists.txt
文件# requirement of cmake version
cmake_minimum_required(VERSION 3.10)
# project name
set(name opencv_test)
PROJECT(${name})
message(STATUS "project name: ${name}")
# find required opencv
set(OpenCV_DIR "C:\\OpenCV\\opencv\\build\\x64\\vc15\\lib")
# set(OpenCV_DIR "C:\\OpenCV\\opencv\\build\\") # 这两个目录中都包含 OpenCVConfig.cmake 文件,两种设置都可以构建项目
find_package(OpenCV REQUIRED)
message(STATUS "OpenCV library status:")
message(STATUS " config: ${OpenCV_DIR}")
message(STATUS " version: ${OpenCV_VERSION}")
message(STATUS " libraries: ${OpenCV_LIBS}")
message(STATUS " include path: ${OpenCV_INCLUDE_DIRS}")
# directory of opencv headers
include_directories(${OpenCV_INCLUDE_DIRS})
message(STATUS "OpenCV_INCLUDE_DIRS: ${OpenCV_INCLUDE_DIRS}")
# name of executable file and path of source file
set(SRC_LIST video_capture.cpp)
message(STATUS "SRC_LIST: ${SRC_LIST}")
add_executable(${name} ${SRC_LIST})
# opencv libraries
target_link_libraries(${name} ${OpenCV_LIBS})
message(STATUS "OpenCV_LIBS: ${OpenCV_LIBS}")
注:关于 OpenCV_DIR 的值是 “C:\OpenCV\opencv\build\x64\vc15\lib” 还是 “C:\OpenCV\opencv\build\”
两个路径都可以成功构建 OpenCV 项目,但是在使用 BeyondCompare 软件对比 cmake 构建信息后发现有些不同:
左图为 “C:\OpenCV\opencv\build\x64\vc15\lib” 的输出结果
右图为 “C:\OpenCV\opencv\build\” 的输出结果
“C:\OpenCV\opencv\build\” 目录包含文件如下
打开命令行进入建立的\build
目录,并执行cmake ..
D:\P_project_SRS_cpp\project_1\build>cmake ..
-- Building for: Visual Studio 16 2019
-- Selecting Windows SDK version 10.0.17763.0 to target Windows 10.0.18363.
-- The C compiler identification is MSVC 19.24.28314.0
-- The CXX compiler identification is MSVC 19.24.28314.0
-- Check for working C compiler: C:/Program Files (x86)/Microsoft Visual Studio/2019/Community/VC/Tools/MSVC/14.24.28314/bin/Hostx64/x64/cl.exe
-- Check for working C compiler: C:/Program Files (x86)/Microsoft Visual Studio/2019/Community/VC/Tools/MSVC/14.24.28314/bin/Hostx64/x64/cl.exe -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: C:/Program Files (x86)/Microsoft Visual Studio/2019/Community/VC/Tools/MSVC/14.24.28314/bin/Hostx64/x64/cl.exe
-- Check for working CXX compiler: C:/Program Files (x86)/Microsoft Visual Studio/2019/Community/VC/Tools/MSVC/14.24.28314/bin/Hostx64/x64/cl.exe -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- project name: opencv_test
-- Found OpenCV: C:/OpenCV/opencv/build (found version "4.1.0")
-- OpenCV library status:
-- config: C:\OpenCV\opencv\build\x64\vc15\lib
-- version: 4.1.0
-- libraries: opencv_calib3d;opencv_core;opencv_dnn;opencv_features2d;opencv_flann;opencv_gapi;opencv_highgui;opencv_imgcodecs;opencv_imgproc;opencv_ml;opencv_objdetect;opencv_photo;opencv_stitching;opencv_video;opencv_videoio;opencv_world
-- include path: C:/OpenCV/opencv/build/include
-- OpenCV_INCLUDE_DIRS: C:/OpenCV/opencv/build/include
-- SRC_LIST: video_capture.cpp
-- OpenCV_LIBS: opencv_calib3d;opencv_core;opencv_dnn;opencv_features2d;opencv_flann;opencv_gapi;opencv_highgui;opencv_imgcodecs;opencv_imgproc;opencv_ml;opencv_objdetect;opencv_photo;opencv_stitching;opencv_video;opencv_videoio;opencv_world
-- Configuring done
-- Generating done
-- Build files have been written to: D:/P_project_SRS_cpp/project_1/build
通过visual studio
打开opencv_test.sln
文件,在这里我准备分别生成 64 位的 Debug
与Release
版本的可执行文件(如下图Debug版本生成,Release版本在红框中下拉列表中选择)
再次进入\build
目录,可以看见刚刚生成的\Debug
与\Release
目录,可以进入这两个目录中查看生成的文件(如下图)
\Debug
目录中的文件
\Release
目录中的文件
现在可以双击可执行文件打开相机了(双目相机由于去掉了红外滤光片,图像会偏红)
Debug
模式的执行文件运行结果
Release
模式的执行文件运行结果
1. 首先需要确定 cmake 的最低版本号,这个命令不是强制性的。
cmake 的命令大小写无关,比如命令find_package
等价于FIND_PACKAGE
,但是在写CMakeLists.txt 文件时尽量保证一致性。
cmake_minimum_required(VERSION 3.10)
2. 然后需要设置项目名称
set(name opencv_test)
PROJECT(${name})
message(STATUS “project name: ${name}”)
这里使用set
命令语法为,它可以显示地定义变量2。用 set 将变量 name 赋值 opencv_test
SET(VAR [VALUE] [CACHE TYPE DOCSTRING [FORCE]])
接下来使用project
命令(格式如下)将项目名称通过引用变量${name}
将项目名设定为 opencv_test。(name:变量;${name}:引用 name 变量)4。 这个指令隐式的定义了两个 cmake 变量:
以及
,这里
为 OPENCV_TEST
。同时 cmake 系统也帮助我们预定义了 PROJECT_BINARY_DIR
和 PROJECT_SOURCE_DIR
变量,他们的值分别跟 OPENCV_TEST_BINARY_DIR
与 OPENCV_TEST_SOURCE_DIR
一致,为了统一起见,建议以后直接使用 PROJECT_BINARY_DIR,PROJECT_SOURCE_DIR,即使修改了工程名称,也不会影响这两个变量。4。
PROJECT(projectname [CXX] [C] [Java])
-- OPENCV_TEST_BINARY_DIR D:/P_project_SRS_cpp/project_1/build
-- OPENCV_TEST_SOURCE_DIR D:/P_project_SRS_cpp/project_1/build
-- PROJECT_BINARY_DIR D:/P_project_SRS_cpp/project_1/build
-- PROJECT_SOURCE_DIR D:/P_project_SRS_cpp/project_1/build
message
的语法。这个指令用于向终端输出用户定义的信息,包含了三种类型:
SEND_ERROR
,产生错误,生成过程被跳过。
SATUS
,输出前缀为—的信息。
FATAL_ERROR
,立即终止所有 cmake 过程.
MESSAGE([SEND_ERROR | STATUS | FATAL_ERROR] “message to display”…)
3. 接下来搜索编译的 OpenCV 包
使用find_package
命令从外部项目中搜寻并载入配置 ,
变量将会被设置如果目标包被找到。
set(OpenCV_DIR “C:\OpenCV\opencv\build\x64\vc15\lib”)
find_package(OpenCV REQUIRED)
为了找到(find_package
) OpenCV 包,我们需要设置(set
) OpenCV_DIR 变量,它的值为包含 OpenCVConfig.cmake 文件的目录的绝对值,如准备1中所说的,我的 OpenCVConfig.cmake 文件路径为:
C:\OpenCV\opencv\build\x64\vc15\lib
find_package
命令用来调用预定义在CMAKE_MODULE_PATH
下的Find
模块,你也可以自己定义.cmake Find
模块,通过SET(CMAKE_MODULE_PATH dir)
将其放入工程的某个目录中供工程使用2。
如果包找到以后,一些变量将会被定义,比如(见 OpenCVConfig.cmake 文件中内容):
# find_package(OpenCV REQUIRED core OPTIONAL_COMPONENTS viz)
#
# If the module is found then OPENCV__FOUND is set to TRUE.
#
# This file will define the following variables:
# - OpenCV_LIBS : The list of all imported targets for OpenCV modules. (OpenCV 模块的所有导入目标的列表,.lib 文件)
# - OpenCV_INCLUDE_DIRS : The OpenCV include directories. (OpenCV 的包含目录,.h/.hpp 文件)
# - OpenCV_COMPUTE_CAPABILITIES : The version of compute capability.
# - OpenCV_ANDROID_NATIVE_API_LEVEL : Minimum required level of Android API.
# - OpenCV_VERSION : The version of this OpenCV build: "4.1.0"
# - OpenCV_VERSION_MAJOR : Major version part of OpenCV_VERSION: "4"
# - OpenCV_VERSION_MINOR : Minor version part of OpenCV_VERSION: "1"
# - OpenCV_VERSION_PATCH : Patch version part of OpenCV_VERSION: "0"
# - OpenCV_VERSION_STATUS : Development status of this build: ""
#
# Advanced variables:
# - OpenCV_SHARED : Use OpenCV as shared library
# - OpenCV_INSTALL_PATH : OpenCV location
# - OpenCV_LIB_COMPONENTS : Present OpenCV modules list
# - OpenCV_USE_MANGLED_PATHS : Mangled OpenCV path flag
#
# Deprecated variables:
# - OpenCV_VERSION_TWEAK : Always "0"
OpenCV 中的目录解释6
包含目录(include directory)[OpenCV_INCLUDE_DIRS]:包含 .h 或 .hpp 文件的搜索目录
库目录(library directory)[OpenCV_LIBS]:包含 .lib 文件的搜索目录
在我的配置中,这两个变量的值为:
– OpenCV_INCLUDE_DIRS: C:/OpenCV/opencv/build/include
– OpenCV_LIBS: opencv_calib3d;opencv_core;opencv_dnn;opencv_features2d;opencv_flann;opencv_gapi;opencv_highgui;opencv_imgcodecs;opencv_imgproc;opencv_ml;opencv_objdetect;opencv_photo;opencv_stitching;opencv_video;opencv_videoio;opencv_world
4. 引入头文件搜索,使工程找到 OpenCV 的 .h.hpp 文件
# directory of opencv headers
include_directories(${OpenCV_INCLUDE_DIRS})
message(STATUS "OpenCV_INCLUDE_DIRS: ${OpenCV_INCLUDE_DIRS}")
为了让我们的工程能够找到 OpenCV 包中的 .h.hpp 头文件,我们需要引入一个新的指令INCLUDE_DIRECTORIES
,这条指令可以用来向工程添加多个特定的头文件搜索路径2,在此项目中,dir
的值为${OpenCV_INCLUDE_DIRS}
即C:/OpenCV/opencv/build/include
,其完整语法为:
INCLUDE_DIRECTORIES([AFTER|BEFORE] [SYSTEM] dir1 dir2 …)
5. 为项目添加 OpenCV 的共享库(.lib)
# opencv libraries
target_link_libraries(${name} ${OpenCV_LIBS})
message(STATUS "OpenCV_LIBS: ${OpenCV_LIBS}")
使用target_link_libraries
命令为项目可执行文件添加需要链接的共享库,${name}
为 opencv_text.exe
${OpenCV_LIBS}
的值参见上文。TARGET_LINK_LIBRARIES 的全部语法是:
TARGET_LINK_LIBRARIES(target library1
library2
…)
6. 让工程生成一个可执行文件 .exe
# name of executable file and path of source file
set(SRC_LIST video_capture.cpp)
message(STATUS "SRC_LIST: ${SRC_LIST}")
add_executable(${name} ${SRC_LIST})
定义了这个工程会生成一个文件名为 hello 的可执行文件,相关的源文件是 SRC_LIST 中定义的源文件列表,在这个项目中 SRC_LIST 只有一个源文件,即video_capture.cpp
。
Anaconda介绍、安装及使用教程:https://zhuanlan.zhihu.com/p/32925500 ↩︎
Cmake 实践(pdf):http://file.ncnynl.com/ros/CMake Practice.pdf ↩︎ ↩︎ ↩︎ ↩︎
cmake 学习笔记(一):https://blog.csdn.net/dbzhang800/article/details/6314073 ↩︎
調整 CMakeLists.txt for OpenCV 4.1.0(已安裝多版本opencv@2, opencv@3…):https://davistseng.blogspot.com/2019/06/cmakeliststxt-for-opencv-410opencv2.html ↩︎ ↩︎ ↩︎
命令行tree命令生成文件树:https://kingganzeng.github.io/命令行tree命令生成文件树/ ↩︎
包含目录、库目录、附加包含目录、附加库目录、附加依赖项之详解:https://blog.csdn.net/u012043391/article/details/54972127 ↩︎