opencv版本
opencv2.x版本和3.x版本有很大的区别,很多东西都不兼容,有时候需要用到2.x版本的一些库,而在3.x版本已经不在了,网上看到一些大牛是直接将2.x的函数移植到3.x版本。这次用到2.x版本的东西,而官网下载的opecv2.x版本最多支持到vs2013,为了在vs2017上用openv2.x,只得参照网上的资料,自己用vs2017重新编译了一遍。
在vs中配置opencv
我们在编译好opencv以后,如何在自己的项目中使用呢?这个网上的资料也有很多,主要是对我们的opencv项目的属性管理器中的VC++目录进行配置,将自己编译出的opencv目录包含到自己新建的工程中。然后在链接器中添加依赖。值得一说的是,需要添加的依赖有几十个.lib文件需要添加上,挨个复制太累了,我是写个脚本把文件名都读出来添加进去,后来看到可以这样:lib*.lib”。
在vs中生成动态链接库
当然,我们的项目是分块做的,我们添加了依赖和包含目录的项目是不能脱离opencv环境运行的。我们可以在包含了opencv第三方lib和dll基础上,生成可独立于opencv环境运行的dll文件。
参考1参考2 总结如下
- 新建一个dll项目
- 包含opencv目录
- 添加opencv依赖
源文件中包含3个文件 dllmain.cpp opencv_dll.cpp 和stdafx.cpp,这里的dllmain.cpp类似于C中的main函数,但是我们的代码并不是在这个dllmain函数中,它只是相当于一个入口和出口,当函数执行时先进入这个dllmain函数中,然后再执行其他函数,我们需要定义的函数是写在opencv_dll.cpp这个文件中的,其实和生成可执行文件的程序编写一样。
这里贴上我参考的博客的代码吧。
#include "stdafx.h"
#include<iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include<opencv2\imgproc\imgproc.hpp>
#include <string.h>
#include "legacy/legacy.hpp"
using namespace std;
using namespace cv;
extern "C" _declspec(dllexport)
int opencv_dll_main(const char * sImagePath)
{
// 读入一张图片(测试图)
Mat img = imread(sImagePath), tempImage;
// 创建一个名为 "处理后图片"的窗口
cvNamedWindow("处理后图片", 0);
cvResizeWindow("处理后图片", int(img.rows), int(img.rows));
cvNamedWindow("原始图片", 0);
cvResizeWindow("原始图片", int(img.rows), int(img.rows));
//进行颜色空间的转换
cvtColor(img, tempImage, COLOR_LBGR2Lab);
// 在窗口中显示测试图
imshow("处理后图片", tempImage);
imshow("原始图片", img);
printf("调用成功666");
// 等待操作,关闭显示
waitKey(0);
return 0;
}
在新项目中调用生成的dll
如参考2所说,有两种调用方式:
- 显式调用:使用LoadLibray载入动态链接库、使用GetProcAddress获取某函数地址。
- 隐式调用:可以使用#pragma comment(lib, “XX.lib”)的方式,也可以直接将XX.lib加入到工程中。
一开始参考的博客是用了隐式调用,可是我一直没调出来,这里记一下显示调用:
- LoadLibrary,顾名思义,该函数的作用是加载DLL文件,因此该函数的参数就是你想要使用的DLL文件;
- GetProcAddress,大概意思是获得欲使用函数的地址,其有两个参数,一个是后面会提到的句柄,另外一个就是DLL中的函数;
- FreeLibrary,释放动态链接库。
#include"stdafx.h"
#include<iostream>
#include<Windows.h>//这个头文件非常重要,必须加上!
using namespace std;
typedef int(*dllfunc)(const char * a);//这里的dllfun形式上和我们生成的DLL文件中的函数一致,我们的dll中定义的函数有两个整型参数,因此这里也是int a,int b
int main()
{
HINSTANCE hdll;//定义一个句柄实例,来获取dll的实例地址
//这里为简单起见,我们直接将生成的multiply.dll文件复制到当前项目下,否则下面一句你需要替换成dll的地址
hdll = LoadLibrary("opencv_dll.dll");//加载生成的dll文件,因为我们把生成的dll文件复制到当前项目目录下了,所以直接写就行了
//下面判断当前dll是否加载成功
if (hdll == NULL)
{
cout << "DLL加载失败" << endl;
return 0;
}
//如果通过上面则表明加载成功了,下面我们需要取出dll里面函数的地址
dllfunc add_obj = (dllfunc)GetProcAddress(hdll, "opencv_dll_main");//此处两个参数一个是我们的句柄,另外一个是dll中函数名,取出来给add_obj
//同样,取址是否成功呢?判断一下!
if (add_obj == NULL)
{
cout << "获取DLL中函数地址失败!" << endl;
return 0;
}
const char * imagePath = "F:\\100MSDCF\\test.jpg";
//获取函数地址成功后,我们就可以使用dll中的函数了
add_obj( imagePath);
FreeLibrary(hdll);
return 0;
}
当然如果dll中封装了多个函数,我们可以在GetProcAddress(hdll, "opencv_dll_main")
这个函数中选择要用到的函数名。
这是我想要的结果,就是根据原来的蓝色大体位置,得到精确的轮廓。