OpenCV 4.12.0
开源计算机视觉
加载中...
搜索中...
无匹配项
如何在“Microsoft Visual Studio”中构建使用 OpenCV 的应用程序

上一个教程: Windows 中的安装
下一个教程: Image Watch:在 Visual Studio 调试器中查看内存中的图像

原始作者Bernát Gábor
兼容性OpenCV >= 3.0
警告
本教程可能包含过时的信息。

我在这里描述的所有内容都适用于 OpenCV 的 C\C++ 接口。我假设您已经阅读并成功完成了 Windows 中的安装 教程。因此,在您继续进行任何操作之前,请确保您有一个 OpenCV 目录,其中包含 OpenCV 头文件和二进制文件,并且您已按照此处描述设置了环境变量 设置 OpenCV 环境变量并将其添加到系统路径

我们分发的 OpenCV 库在 Microsoft Windows 操作系统上采用动态链接库 (DLL) 形式。 它们的优点是库的所有内容仅在运行时按需加载,并且无数程序可以使用同一库文件。 这意味着如果您有十个应用程序使用 OpenCV 库,则无需为每个应用程序都准备一个版本。 当然,您需要在要运行应用程序的所有系统上都拥有 OpenCV 的 dll

另一种方法是使用具有 lib 扩展名的静态库。 您可以通过使用我们的源文件来构建它们,如 Windows 中的安装 教程中所述。 当您使用此方法时,库将内置到您的 exe 文件中。 因此,用户没有机会出于某种原因删除它们。 缺点是您的应用程序会更大,并且在启动期间加载它会花费更多时间。

要使用 OpenCV 构建应用程序,您需要做两件事

  • 告诉 编译器 OpenCV 库的样子。 您可以通过显示它头文件来做到这一点。
  • 告诉 链接器从哪里获取 OpenCV 的函数或数据结构(当需要它们时)。

    如果您使用 lib 系统,则必须设置库文件所在的路径,并指定在其中查找哪个库。 在构建过程中,链接器将查找这些库,并将所有 已使用 函数和数据结构的定义和实现添加到可执行文件中。

    如果您使用 DLL 系统,则必须再次指定所有这些,但是现在出于不同的原因。 这是一个 Microsoft OS 特有的东西。 似乎链接器需要知道在运行时在 DLL 中的什么位置搜索数据结构或函数。 此信息存储在 lib 文件中。 然而,它们不是静态库。 它们是所谓的导入库。 这就是为什么当您在 Windows 中制作一些 DLL 时,您最终也会得到一些 lib 扩展库的原因。 好处是在运行时只需要 DLL

要将所有这些信息传递给 Visual Studio IDE,您可以全局进行(因此您未来的所有项目都将获得此信息)或本地进行(因此仅适用于您当前的项目)。 全局方法的优点是您只需要做一次; 但是,一直用所有这些信息来堆积您的项目可能是不可取的。 如果是全局方法,您如何执行取决于您使用的 Microsoft Visual Studio。 有 2008 和以前的版本 以及 2010 版本 的执行方式。 在本教程的全局部分中,我将展示主要区别是什么。

Visual Studio 中项目的基础项是解决方案。 一个解决方案可以包含多个项目。 项目是应用程序的构建块。 每个项目都将实现某些功能,并且您将有一个主项目,您可以在其中将这个项目难题拼凑在一起。 对于许多简单的应用程序(例如许多教程),您不需要将应用程序分解为模块。 在这些情况下,您的主项目将是唯一存在的项目。 现在,通过转到“文件”–>“新建”–>“项目”菜单选择,在 Visual Studio 中创建一个新解决方案。 选择 Win32 控制台应用程序 作为类型。 输入其名称并选择创建它的路径。 然后在即将出现的对话框中,确保创建一个空项目。

本地方法

每个项目都与其他项目分开构建。 因此,每个项目都有自己的规则包。 在此规则包中存储了 IDE 需要知道的所有信息才能构建您的项目。 对于任何应用程序,至少有两种构建模式:ReleaseDebugDebug 具有许多功能,这些功能的存在是为了您可以更轻松地在应用程序中查找和解决错误。 相比之下,Release 是一个优化版本,其目标是使应用程序运行得尽可能快或尽可能小。 您可能会发现这些模式还需要在构建期间使用不同的规则。 因此,每种构建模式都存在不同的规则包。 这些规则包在 IDE 中称为项目属性,您可以通过使用属性管理器来查看和修改它们。 您可以通过“查看”–>“属性页”来调出它(对于 Visual Studio 2013 及更高版本,请转到“查看”–>“其他窗口”–>“属性管理器”)。 展开它,您可以看到现有的规则包(称为属性表)。

这些属性表中真正有用的东西是,您可以一次创建一个规则包,以后只需将其添加到您的新项目中即可。 创建一次并在以后重用它。 我们想要创建一个新的 属性表,其中将包含编译器和链接器需要知道的所有规则。 当然,我们将需要一个单独的 Debug 和 Release 版本。 从 Debug 版本开始,如下图所示

例如,使用 OpenCV_Debug 名称。 然后通过选择工作表,右键单击 ->“属性”。 在下面,我将展示如何在本地设置 OpenCV 规则,因为我认为用我不使用的自定义规则来污染项目是不必要的。 转到 C++ 组的“常规”条目,然后在“附加包含目录”下添加 OpenCV include 的路径。 如果您没有“C/C++”组,则应向项目添加任何 .c/.cpp 文件。

$(OPENCV_DIR)\..\..\include

当添加第三方库设置时,通常最好利用环境变量背后的强大功能。 OpenCV 库的完整位置可能会在每个系统上发生变化。 此外,您甚至可能出于某种原因最终移动安装目录。 如果您在属性表中提供显式路径,则当您将其传递给具有不同 OpenCV 安装路径的其他人时,您的项目将最终无法正常工作。 此外,修复此问题需要手动修改每个显式路径。 一个更优雅的解决方案是使用环境变量。 您放在以美元符号开头的括号内的任何内容将在运行时替换为当前环境变量值。 这就发挥了我们在之前的教程 设置 OpenCV 环境变量并将其添加到系统路径 中已经完成的环境变量设置。

接下来,转到“链接器”–>“常规”,然后在“附加库目录”下添加 libs 目录

$(OPENCV_DIR)\lib

然后,您需要指定链接器应在其中查找的库。 为此,请转到“链接器”–>“输入”,然后在“附加依赖项”条目下添加要使用的所有模块的名称

库的名称如下

opencv_(模块名称)(您使用的库的版本号)d.lib

最新版本的完整列表将包含

opencv_calib3d300d.lib
opencv_core300d.lib
opencv_features2d300d.lib
opencv_flann300d.lib
opencv_highgui300d.lib
opencv_imgcodecs300d.lib
opencv_imgproc300d.lib
opencv_ml300d.lib
opencv_objdetect300d.lib
opencv_photo300d.lib
opencv_shape300d.lib
opencv_stitching300d.lib
opencv_superres300d.lib
opencv_ts300d.lib
opencv_video300d.lib
opencv_videoio300d.lib
opencv_videostab300d.lib

或者,您的 OpenCV 下载可能已构建为一个大的 .lib 文件。 通过查看 OpenCV\build\architecture\vc14\lib 进行检查。 在这种情况下,您要添加的全部内容是,对于 3.3.0 版本

opencv_world330.lib

末尾的字母 d 只是表示这些是调试所需的库。 现在单击“确定”保存,并在 Release 规则部分内的新属性中执行相同的操作。 确保省略库名称中的 d 字母,并使用它们上方的保存图标保存属性表。

您可以在项目的目录中找到您的属性表。 此时,最好将它们备份到一些特殊目录中,以便将来在您创建 OpenCV 项目时始终可以随时使用它们。 请注意,对于 Visual Studio 2010,文件扩展名为 props,而对于 2008,则为 vsprops

下次当您创建一个新的 OpenCV 项目时,只需使用“属性管理器”中的“添加现有属性表...”菜单项即可轻松添加 OpenCV 构建规则。

全局方法

如果您觉得为每个项目添加属性页面太麻烦,您也可以将此规则添加到“全局属性页面”。 但是,这仅适用于其他包含目录和库目录。 您仍然需要手动指定要使用的库的名称,例如:使用属性页面。

在 Visual Studio 2008 中,您可以在以下位置找到它:“工具”–>“选项”–>“项目和解决方案”–>“VC++ 目录”。

在 Visual Studio 2010 中,这已移至全局属性表,该属性表会自动添加到您创建的每个项目中

该过程与本地方法的情况相同。 只需使用环境变量 OPENCV_DIR 添加包含目录即可。

测试一下!

现在尝试一下,下载我们的小测试 源代码 或从 OpenCV 源的示例代码文件夹中获取它。 将其添加到您的项目并构建它。 这是它的内容

#include <opencv2/core.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main( int argc, char** argv )
{
if( argc != 2)
{
cout <<" 用法: " << argv[0] << " ImageToLoadAndDisplay" << endl;
return -1;
}
Mat image;
image = imread(argv[1], IMREAD_COLOR); // 读取文件
if( image.empty() ) // 检查无效输入
{
cout << "无法打开或找到图像" << std::endl ;
return -1;
}
namedWindow( "显示窗口", WINDOW_AUTOSIZE ); // 创建一个用于显示的窗口。
imshow( "显示窗口", image ); // 在其中显示我们的图像。
waitKey(0); // 等待窗口中的按键
return 0;
}
n 维密集数组类
定义 mat.hpp:830
cv::getTickFrequency
double getTickFrequency()
int main(int argc, char *argv[])
定义 highgui_qt.cpp:3
定义 core.hpp:107
STL 命名空间。

您可以从两个位置启动 Visual Studio 构建。 可以从 IDE 内部启动(键盘组合:Control-F5),也可以导航到您的构建目录并双击启动应用程序。 问题是这两者相同。 当您从 IDE 启动它时,其当前工作目录是项目目录,否则它是应用程序文件当前所在的文件夹(因此通常是您的构建目录)。 此外,如果是从 IDE 启动,控制台窗口在完成后不会关闭。 它将等待您的击键。

当您在代码中编写打开和保存命令时,记住这一点很重要。 您的资源将相对于您的工作目录保存(并在打开时查询!!!)。 除非您为 I/O 函数提供完整的显式路径作为参数。 在上面的代码中,我们打开 这个 OpenCV 徽标。 在启动应用程序之前,请确保将图像文件放在当前工作目录中。 修改代码中的图像文件名,以便在其他图像上进行测试。 运行它,瞧

Visual Studio 中的命令行参数

在我们将来的某些教程中,您会看到程序的主要输入方法将是通过给出运行时参数。 为此,您可以只启动一个命令窗口(在开始菜单中按 cmd + Enter),导航到您的可执行文件并使用参数启动它。 因此,例如,对于我的上一个项目,这将如下所示

D
CD OpenCV\MySolutionName\Release
MySolutionName.exe exampleImage.jpg

在这里,我首先更改了我的驱动器(如果您的项目不在 OS 本地驱动器上),导航到我的项目并使用示例图像参数启动它。 虽然在 Linux 系统下使用控制台窗口是很常见的,但在 Microsoft Windows 上很多人几乎从未使用过它。 此外,在您测试应用程序时一遍又一遍地添加相同的参数在某种程度上是一项繁琐的任务。 幸运的是,在 Visual Studio 中有一个菜单可以自动完成所有这些操作

在此处指定输入的名称,并且当您从 Visual Studio 环境启动应用程序时,您将自动传递参数。 在下一个介绍性教程中,您将看到对上一个源代码的深入解释:图像入门