Download
Install 下载 opencv-3.4.11-vc14_vc15.exe
文件,双击安装(其实只是一个解压过程)。
有的教程中会建议将解压后的 OpenCV 下的某些路径添加到系统环境变量中;这里换一种方法,仅修改 VS 的工程属性,无需添加系统环境变量。
VS2017 配置 参考OpenCV 4.1.0 + Visual Studio 2019 开发环境搭建 超级简单
准备文件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 - <sln > 解决方案文件夹 - x64 - Debug // 将 opencv\build\x64\vc15\bin 路径下的 3 个.dll 文件拷贝到这里 - <proj > .exe - opencv_world3411.dll - opencv_ world3411d.dll - opencv_ffmpeg3411_ 64.dll - Release - <proj > .exe - opencv_world3411.dll - opencv_ world3411d.dll - opencv_ffmpeg3411_ 64.dll - <proj > 项目文件夹 - Debug - include - opencv2 // 从 opencv\build\include 路径下将整个 opencv2 文件夹拷贝到这里 - lib // 将 opencv\build\x64\vc15\lib 路径下的两个.lib 文件拷贝到这里 - opencv_world3411.lib - opencv_ world3411d.lib - src - main.cpp - x64 - Debug - Debug
配置
LIB 在 解决方案资源管理器
右击项目名 ->属性
-> 链接器
-> 常规
-> 附加库目录
: 将 lib 文件夹路径添加到这里,或者直接用相对路径表示,添加lib
即可. 在 解决方案资源管理器
右击项目名 ->属性
-> 链接器
-> 输入
-> 附加依赖项
: 将 lib 文件名添加到这里, 例如 opencv_world3411d.lib
.
INCLUDE 在 解决方案资源管理器
右击项目名 ->属性
->C/C++
-> 常规
-> 附加包含目录
: 将 include 文件夹路径添加到这里,或者直接用相对路径表示,添加include
即可.
测试 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 #include <iostream> #include "opencv2/opencv.hpp" using namespace std;using namespace cv;int main () { cout << "OpenCV Test:" << endl; Mat img = imread ("./images/demo.jpg" ); imshow ("demo" , img); waitKey (6000 ); return 0 ; }
在图片中写入中文字符
使用 OpenCV 自带的 cv::putText() 函数往图片里写入中文字符时无法正常显示,而是显示为 “???”.
要解决这个问题, 在 Windows 平台上可以调用 Windows API 里的 HDC 系列函数来完成字符绘制,封装后提供的接口为 cv::putTextZH()
.
main.cpp 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 #include "cv_puttextzh.h" int main () { cv::Mat image = cv::Mat (500 , 500 ,CV_8UC3, cv::Scalar (144 , 238 , 144 )); cv::putTextZH ( image, " 你好!OpenCV" , cv::Point (image.cols/3 , image.rows / 2 ), CV_RGB (255 , 255 , 0 ), 30 ); cv::imshow (" 中文图窗 " , image); cv::waitKey (0 ); return 0 ; }
1 2 3 4 5 > ls CMakeLists.txt main.cpp cv_puttextzh.h > mkdir build > cd build > cmake .. -A x64 -DOpenCV_DIR =D:/OpenCV/opencv/build/x64/vc15/lib
如果是其他平台,在 OpenCV 显示中文 | 知乎 中也有解决方案,但需要结合 freetype 和 harfbuzz 重新编译 opencv_contrib.
常用颜色 BGR 值 cv_color_def.h >folded 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 #ifndef CV_COLOR_DEF_H #define CV_COLOR_DEF_H #include <opencv2/core/types.hpp> #define CV_COLOR_RED cv::Scalar(0,0,255) #define CV_COLOR_GREEN cv::Scalar(0,255,0) #define CV_COLOR_BLUE cv::Scalar(255,0,0) #define CV_COLOR_DARKGRAY cv::Scalar(169,169,169) #define CV_COLOR_DARKRED cv::Scalar(0,0,139) #define CV_COLOR_ORANGERED cv::Scalar(0,69,255) #define CV_COLOR_CHOCOLATE cv::Scalar(30,105,210) #define CV_COLOR_GOLD cv::Scalar(10,215,255) #define CV_COLOR_YELLOW cv::Scalar(0,255,255) #define CV_COLOR_OLIVE cv::Scalar(0,128,128) #define CV_COLOR_LIGHTGREEN cv::Scalar(144,238,144) #define CV_COLOR_DARKCYAN cv::Scalar(139,139,0) #define CV_COLOR_SKYBLUE cv::Scalar(230,216,173) #define CV_COLOR_INDIGO cv::Scalar(130,0,75) #define CV_COLOR_PURPLE cv::Scalar(128,0,128) #define CV_COLOR_PINK cv::Scalar(203,192,255) #define CV_COLOR_DEEPPINK cv::Scalar(147,20,255) #define CV_COLOR_VIOLET cv::Scalar(238,130,238) #endif
Trackbar 滑动条 TrackbarDemo.h >folded 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 #include <opencv2/opencv.hpp> #include <opencv2/core/utils/logger.hpp> cv::SimpleBlobDetector::Params pBLOBDetector; cv::Mat src; int iThStep = 10 ;int iMinth = 10 ;int iMaxth = 200 ;int iMinBt = 10 ;int iMinar = 10 ;int iMaxar = 1500 ;int iMinCir = 0 ;int iMinIne = 0 ;int iMinCon = 0 ;void detect (int , void *) { pBLOBDetector.thresholdStep = iThStep; pBLOBDetector.minThreshold = iMinth; pBLOBDetector.maxThreshold = iMaxth; pBLOBDetector.minRepeatability = 2 ; pBLOBDetector.minDistBetweenBlobs = iMinBt; pBLOBDetector.filterByColor = true ; pBLOBDetector.blobColor = 0 ; pBLOBDetector.filterByArea = true ; pBLOBDetector.minArea = iMinar; pBLOBDetector.maxArea = iMaxar; pBLOBDetector.filterByCircularity = true ; pBLOBDetector.minCircularity = iMinCir * 0.01 ; pBLOBDetector.maxCircularity = (float )3.40282e+038 ; pBLOBDetector.filterByInertia = true ; pBLOBDetector.minInertiaRatio = iMinIne * 0.01 ; pBLOBDetector.maxInertiaRatio = (float )3.40282e+038 ; pBLOBDetector.filterByConvexity = true ; pBLOBDetector.minConvexity = iMinCon * 0.01 ; pBLOBDetector.maxConvexity = (float )3.40282e+038 ; cv::Ptr<cv::SimpleBlobDetector> blob = cv::SimpleBlobDetector::create (pBLOBDetector); std::vector<cv::KeyPoint> key_points; blob->detect (src, key_points); cv::Mat outImg; cv::drawKeypoints (src, key_points, outImg, cv::Scalar (0 , 0 , 255 )); cv::imshow ("blob" , outImg); } void main () { src = cv::imread ("C:/Users/siyou/Desktop/af8aed46ec80b30b72c45cad6c3b9cd6.png" , cv::IMREAD_GRAYSCALE); if (src.empty ()) { std::cout << "Cannot load image" << std::endl; return ; } cv::imshow ("src" , src); cv::namedWindow ("Detectwindow" , cv::WINDOW_NORMAL); cv::createTrackbar (" 最小圆度 " , "Detectwindow" , &iMinCir, 100 , detect); cv::createTrackbar (" 最小惯性率 " , "Detectwindow" , &iMinIne, 100 , detect); cv::createTrackbar (" 最大凸度 " , "Detectwindow" , &iMinCon, 100 , detect); cv::createTrackbar (" 阈值步距 " , "Detectwindow" , &iThStep, 100 , detect); cv::createTrackbar (" 最小阈值 " , "Detectwindow" , &iMinth, 255 , detect); cv::createTrackbar (" 最大阈值 " , "Detectwindow" , &iMaxth, 255 , detect); cv::createTrackbar (" 最小距离 " , "Detectwindow" , &iMinBt, 255 , detect); cv::createTrackbar (" 最小面积 " , "Detectwindow" , &iMinar, 1000 , detect); cv::createTrackbar (" 最大面积 " , "Detectwindow" , &iMaxar, 5000 , detect); detect (0 , 0 ); cv::waitKey (0 ); }
OpenCV Contrib 在 OpenCV 中有部分模块 (modules) 通常没有稳定的 API, 并且未经充分测试, 因此, 它们不应该作为 OpenCV 正式发行版的一部分发布. 这些模块被单独开发, 并首先在 opencv_contrib 存储库中发布. 直至模块成熟并普及时, 才将其移至中央 OpenCV 存储库.
下载 要使用 opencv_contrib
必须将其与 OpenCV
主体部分联合编译, 因此需要下载具有相同版本号的源码. 这里统一使用 3.4.11
. 从以下地址下载 OpenCV
和opencv_contrib
的源码包, 如果 github 下载太慢可以尝试 gitee 极速下载. 将源码包解压到统一目录下,分别命名为 sources
和opencv_contrib
. 并新建 build
文件夹.
1 2 3 4 - <OpenCV_Contrib> - sources # opencv-3.4.11.zip 解压并重命名得到 - opencv_contrib # opencv_contrib-3.4.11.zip 解压得到 - build # 新建空文件夹
OpenCV 3.4.11
opencv_contrib 3.4.11
编译安装 打开CMake-Gui
, 配置如下:
Where is the source code: <OpenCV_Contrib>/sources
Where to build the binaries: <OpenCV_Contrib>/build
点击一次 Configure
修改配置:
BUILD_opencv_world [√]
OPENCV_ENABLE_NONFREE [√]
OPENCV_EXTRA_MODULES_PATH: <OpenCV_Contrib>/opencv_contrib/modules
并再次点击 Configure
. 之后 CMake 会从网上下载部分文件, 但往往因为网速问题而下载失败,输出红色 warning,此时可以按照提示去查看 <OpenCV_Contrib>/build/CMakeDownloadLog.txt
, 其中记录了 CMake 试图从某些网址下载文件放到<OpenCV_Contrib>/sources/.cache/
相应路径下. 以如下片段为例.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 #do_copy "face_landmark_model.dat" "7505c44ca4eb54b4ab1e4777cb96ac05" "https://raw.githubusercontent.com/opencv/opencv_3rdparty/8afa57abc8229d611c4937165d20e2a2d9fc5a12/face_landmark_model.dat" "D:/OpenCV/opencv/build_contrib/testdata/cv/face/" #missing "D:/OpenCV/opencv/build_contrib/testdata/cv/face//face_landmark_model.dat" #check_md5 "D:/OpenCV/opencv/sources/.cache/data/7505c44ca4eb54b4ab1e4777cb96ac05-face_landmark_model.dat" #mismatch_md5 "D:/OpenCV/opencv/sources/.cache/data/7505c44ca4eb54b4ab1e4777cb96ac05-face_landmark_model.dat" "cbe7f803f749dbe38cf6445036349412" #delete "D:/OpenCV/opencv/sources/.cache/data/7505c44ca4eb54b4ab1e4777cb96ac05-face_landmark_model.dat" #cmake_download "D:/OpenCV/opencv/sources/.cache/data/7505c44ca4eb54b4ab1e4777cb96ac05-face_landmark_model.dat" "https://raw.githubusercontent.com/opencv/opencv_3rdparty/8afa57abc8229d611c4937165d20e2a2d9fc5a12/face_landmark_model.dat" #try 1 # timeout on name lookup is not supported # Trying 185.199.108.133:443... # TCP_NODELAY set # connect to 185.199.108.133 port 443 failed: Timed out # Failed to connect to raw.githubusercontent.com port 443: Timed out # Closing connection 0 #
在该段日志中,CMake 试图从 “https://raw.githubusercontent.com/opencv/opencv_3rdparty/8afa57abc8229d611c4937165d20e2a2d9fc5a12/face_landmark_model.dat" 下载 “face_landmark_model.dat” 文件放到 “D:/OpenCV/opencv/build_contrib/testdata/cv/face/“ 路径下. 但是因为下载失败,<...>/cv/face/"
路径下没有找到该文件. 并且去 D:/OpenCV/opencv/sources/.cache/data/
路径下查看, 发现其中有一个命名为 7505c44ca4eb54b4ab1e4777cb96ac05-face_landmark_model.dat
的空文件,大小为 0Kb. 因为是空的,所以在接下来的 md5 校验中不匹配.CMake delete 了该文件, 又尝试去网络上下载,但由于网络超时, 下载失败.
通过分析以上日志, 可以得出解决办法:
手动从以上路径下载相应文件,重命名后放到 <OpenCV_Contrib>/sources/.cache/
相应路径下,放到该路径下的文件名应当类似于7505c44ca4eb54b4ab1e4777cb96ac05-face_landmark_model.dat
, 文件名前是一段 md5 校验码.
或者: 直接下载文件复制到 <OpenCV_Contrib>/build/testdata/cv/face//face_landmark_model.dat
, 此时文件名前不用加 md5 码.
所有文件手动下载后,再次点击Configure
,应当不再输出红色的 warning 信息, 否则还应再次检查日志文件.
点击 Generate
生成 VS2017 解决方案, 点击 Open Project 打开. 在 VS2017 工具栏选择: 生成
-> 批生成
,勾选ALL_BUILD Debug
,ALL_BUILD Release
, INSTALL Debug
, INSTALL Release
四项, 点击 生成
. 等待编译并安装, 之后在build/install/
路径下会生成相应的库文件用于调用.
Reference
在写 OpenCV C++ 程序时经常会看到其内置函数的形参是 cv::InputArray
,cv::OutputArray
等类型; 如果仅仅是调用这些函数, 直接传入 cv::Mat
,std::vector<cv::Mat>
等类型的实参即可. 因为 OpenCV 定义的这些类型可以方便地看出形参是输入参数还是输出参数, 看起来比 const cv::Mat&
,cv::Mat&
要专业些, 所以有些自己写的函数也想用这种类型, 本项目就简单介绍一下这些类型如何使用.
cv::InputArray
是输入参数, 一般可以对标 const cv::Mat&
类型, 在函数定义中使用的时候可以通过 cv::_InputArray::getMat() 获取到真正的 cv::Mat
. 如下函数默认实参为cv::noArray()
, 如果没有显式地传入有效实参, 则src.empty()
为true
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 void test_InputArray (cv::InputArray src = cv::noArray()) { CV_Assert (src.kind ()==cv::_InputArray::MAT); cv::Mat src_mat; if (src.empty ()) { src_mat = cv::Mat::eye (100 ,100 ,CV_8UC1)*255 ; } else { src_mat = src.getMat (); } }
cv::InputArrayOfArrays
实际上就是 cv::InputArray
, 但既然类型名为InputArrayOfArrays
, 一般用于表示const std::vector<cv::Mat>&
, 可以通过getMatVector() 获取到实际的数据.
cv::OutputArray cv::OutputArray
是输出参数, 该类型的变量并没有默认分配内存空间, 需要在函数定义中显式地申请空间. 以下函数默认实参为 cv::noArray()
, 如果用户实际上不需要该数据, 则可以使用该实参, 在函数定义中通过cv::_OutputArray::needed()
判断是否需要, 然后执行相应的操作.
1 2 3 4 5 6 7 8 void test_OutputArray (cv::OutputArray dst = cv::noArray()) { if (dst.needed ()) { cv::Mat mat = cv::Mat::eye (50 ,50 ,CV_8UC1)*255 ; dst.assign (mat); } }
以上函数定义中通过定义 cv::Mat mat
来分配了空间, 然后再通过 assign()
即可将其通过 dst
输出. 还有另一种分配空间的方式:create
, 此时无需 assign
即可输出.
1 2 3 4 5 6 7 8 9 void test_OutputArray (cv::OutputArray dst = cv::noArray()) { if (dst.needed ()) { dst.create (cv::Size (50 ,50 ),CV_8UC1); cv::Mat mat = dst.getMat (); mat = cv::Mat::eye (50 ,50 ,CV_8UC1)*255 ; } }
cv::OutputArrayOfArrays cv::OutputArrayOfArrays
实际上就是 cv::OutputArray
, 但既然类型名为OutputArrayOfArrays
, 一般用于表示std::vector<cv::Mat>&
.assign
前要先通过 create
为其分配空间.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 void test_OutputArrayofArrays (cv::OutputArrayOfArrays dst) { std::vector<cv::Mat> outImages; outImages.push_back (cv::Mat::eye (500 ,500 ,CV_8UC1)*255 ); outImages.push_back (cv::Mat::eye (600 ,600 ,CV_8UC1)*255 ); #if 1 dst.create ((int )outImages.size (), 1 , CV_8UC1); #endif #if 0 int size = (int )outImages.size (); dst.create (1 , &size, CV_8UC1); #endif #if 0 int size[2 ] = {(int )outImages.size (),1 }; dst.create (2 , size, CV_8UC1); #endif dst.assign (outImages); }
分辨 cv::Mat
和std::vector<cv::Mat>
由于 cv::InputArray
与cv::InputArrayOfArrays
实际上是同一种类型, 因此尽管我们约定前者表示 cv::Mat
, 后者表示std::vector<cv::Mat>
, 但这并不是强制的. 为了确保用户传入的实参符合预期, 可以用kind()
来获取实参的类型.
1 CV_Assert (src.kind ()==cv::_InputArray::MAT);
Reference