OpenCV的编译和安装

17 | 03 | 2021

OpenCV的编译和安装

想要使用OpenCV进行图像的处理和开发,就需要先对OpenCV库进行编译。

虽然在Windows下已经有了现成的OpenCV库,但是由于官方提供的库缺少一些关键的功能(例如OpenCV的Nonfree库),因此需要自己编译。

过程记录如下:

0. 准备

准备工作如下:

  1. 安装编译环境。如果是在Windows下就是VS/MingW等编译环境,Linux下就是GCC或其他交叉编译工具链。
  2. 下载OpenCV源码和对应版本的opencv_contrib,放在同一目录下。如下图所示。
  3. Windows下编译,需要安装Cmake。Linux下编译,需要安装Cmake-qt-gui。

1. Windows+VS2015下的OpenCV编译

Windows下的源码编译使用Windows+VS2015进行编译。其他编译环境可以参考。

1.1 Cmake生成OpenCV源码配置

Cmake是用来配置源码的工具。一般一套代码中都包含了各式各样的功能,通过Cmake可以设置哪些功能需要编译,哪些不需要、还可以根据电脑的环境自动配置编译工具和生成目录。

该软件类似于Linux下的Menuconfig。

首先打开Cmake,source code定位到OpenCV源码目录,build the binaries是经过Cmake配置后的文件输出目录,点击Configure。

这时候会要求选择自己的编译器和平台,按照自己的情况选择即可,这里选择VS2015,x64,其他默认。

生成后出现如下界面:

Cmake配置OpenCV可能会需要下载一些文件,不过国内网络环境不一定能下载到,Configure之前可能需要科学上网,或自行补充缺少的文件。

由于我们需要使用NONFREE库的功能,选上NONFREE的复选框,并指定Extra Module path为opencv_contrib下的modules目录。

这里的目录选择一定要用右边的…按钮选择,不要复制粘贴。 因为Cmake里作为路径分隔符的是/(和Linux一致),而Windows下是\。

重新Configure,因为带上了opencv_contrib,所以会多出来新的红色配置项,按照需要修改后继续Configure直到全白。

然后Generate,生成VS的工程文件。

生成完毕,点击Open Project打开生成的工程。

分别使用Debug和release生成Install解决方案:

生成结束后,可以看到编译出的install文件夹,这就是编译后的OpenCV库。

注意: 按照文中的配置方式生成的OpenCV库会有很多的dll文件。 优点:可以根据自己使用的功能来选择使用哪个dll,可以减小项目体积。 缺点:配置会比较麻烦。 不想这么麻烦的话,可以在CMAKE中选择OpenCV_WORLD选项,这样就会生成一个OpenCV_World库。优点就是方便,缺点就是会增大体积。

1.2 OpenCV的环境变量配置

  1. 环境变量配置:新建OpenCV变量,指向编译后的Install文件夹。(这里已经将Install文件夹移出到D:\opencv\build\)
  2. 把编译后文件夹中的
    1
    x64\vc14\bin

    下所有dll文件复制到

    1
    C:\windows\system32

    下。

1.3 VS中添加OpenCV依赖项

这里OpenCV库的目录以 D:\opencv\build\ 为例进行配置:

项目上右键属性:

如图,配置Debug x64下VC++的包含目录和库目录:

包含目录增加以下三个文件夹的引用:

1
2
3
D:\opencv\build\include
D:\opencv\build\include\opencv
D:\opencv\build\include\opencv2

库目录增加:

1
D:\opencv\build\x64\vc14\lib

链接器——输入——附加依赖项,加入

1
x64\vc14\lib

下所有带d(debug)后缀的lib文件(如果之前配置了Opencv_World,则这里只需要一个OpenCV_WorldXXXX.dll):

点击确定,即可完成OpenCV的依赖配置。

2. Linux下的OpenCV配置和编译

Linux下编译OpenCV的流程之前我有写过一篇文章介绍,是将OpenCV2源码交叉编译并在NanoPi下运行,可以对照着进行编译操作。

详细的流程可以参考这里:https://blog.csdn.net/u010034969/article/details/82057405

2.1 Linux下的OpenCV配置和编译

Linux下对OpenCV的编译一般是下面几种情况:

  1. 在Linux上直接编译和运行OpenCV相关的程序,例如直接在服务器上运行,或者是在树莓派等自带系统的硬件上编译并运行。
  2. 在Linux系统上进行交叉编译。

这两种情况的差别就在于CMAKE的第一步需要选择使用什么编译器进行OpenCV的编译,其他的和Windows下编译的流程差不多(交叉编译的话建议修改库文件的安装目录)。

如果是链接到没有图形界面的服务器上进行编译,可以使用cmake-qt-gui+XManager远程进行Cmake的图形配置,配置的方式和Windows下大同小异。

这里建议勾选OPENCV_WORLD选项,后续会方便很多。

另外,如果在Linux下运行时需要有运行图形界面(例如imshow函数)的需求,可勾选GTK和QT的项。

Cmake配置结束后,进入生成的目录执行make和make install即可(make install可能需要使用sudo在root权限下执行),如果没有特殊的配置,生成的库会在/usr/local/lib下。

最后执行一下ldconfig更新一下库即可。

2.2 Linux下的OpenCV依赖配置

Linux下的依赖配置很方便,只要在g++的命令行中增加相关的库即可。

例如,需要带OpenCV库编译stitch.cpp为可执行文件stitch,编译命令如下:

1
g++ stitch.cpp -o stitch -lopencv_world

如果出现了stitch这个可执行文件,且正常运行没问题,说明OpenCV配置和编译成功。

附stitch.cpp的代码,该程序是使用OpenCV自带的图像拼接函数对两张图片进行拼接。

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
#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/stitching.hpp>

using namespace std;
using namespace cv;
bool try_use_gpu = false;             //不使用GPU加速
vector<Mat> imgs;
string result_name = "dst1.jpg";      //输出图像
int main(int argc, char * argv[])
{
    Mat img1 = imread("./11.jpg");  //读取输入图像
    Mat img2 = imread("./22.jpg");

    //imshow("p1", img1);  //在Linux终端下执行,不显示图形界面,因此注释掉imshow函数和下面的waitkey函数
    //imshow("p2", img2);

    if (img1.empty() || img2.empty())
    {
        cout << "Can't read image" << endl;
        return -1;
    }
    imgs.push_back(img1); //将img1加入到vector尾部
    imgs.push_back(img2);

    Stitcher stitcher = Stitcher::createDefault(try_use_gpu);
    // 使用stitch函数进行拼接
    Mat pano;
    Stitcher::Status status = stitcher.stitch(imgs, pano);
    if (status != Stitcher::OK)
    {
        cout << "Can't stitch images, error code = " << int(status) << endl;
        return -1;
    }
    imwrite(result_name, pano);
    Mat pano2 = pano.clone();
    // 显示源图像,和结果图像
    //imshow("全景图像", pano);
    imwrite("dstcv.jpg",pano);
    //if (waitKey() == 27)
        //return 0;
}