封装opencv的函数成dll,独立调用

在opencv的实际使用,经常遇到这种情况,自己在电脑上配置了opencv,写好了opencv的代码工程,在环境变量中加了opencv的dll的路径,这样可以在自己电脑上运行代码。但是如果将该工程拷贝到其他没有配置opencv的电脑上就无法运行。解决办法:在配置了opencv的电脑上(但是在环境变量中没有添加dll的路径),将调用相关函数的代码封装成函数,生成dll文件,拷贝到其他没配置opencv的电脑上,再解析该dll,将该dll中调用的一些opencv的函数涉及到的opencv的dll拷贝下就行
下面自己写了一个例子,作为记载。

1、将相关需要实现的功能封装成函数,生成dll

比如自己要实现一个调用opencv的sift的特征检测和配准的函数,将其封装成dll,再调用。用VS新建一个dll_sift的空的工程,添加dll_sift.h和dll_sift.cpp文件。
–dll_sift.h文件代码如下:

#ifndef DLL_SIFT_H
#define DLL_SIFT_H

#include
// 调用opencv的sift相关的功能需要的头文件
#include "highgui/highgui.hpp"    
#include "opencv2/nonfree/nonfree.hpp"    
#include "opencv2/legacy/legacy.hpp"  

using namespace cv;  
using namespace std;  
#endif

–dll_sift.cpp文件代码如下:

#include"dll_sift.h"

//生成dll文件声明  
extern "C" __declspec(dllexport) void sift(char* src, char* dst);           //sift配准函数
extern "C" __declspec(dllexport) void sift_pixel(char* src);   //sift特征提取函数

void sift(char* src, char* dst)  
{    
    Mat image01=imread(src);    
    Mat image02=imread(dst);  
    imshow("原始测试图像",image01);  
    imshow("基准图像",image02);  

    //灰度图转换  
    Mat image1,image2;    
    cvtColor(image01,image1,CV_RGB2GRAY);  
    cvtColor(image02,image2,CV_RGB2GRAY);  


    //提取特征点    
    SurfFeatureDetector surfDetector(800);  // 海塞矩阵阈值  
    vector keyPoint1,keyPoint2;    
    surfDetector.detect(image1,keyPoint1);    
    surfDetector.detect(image2,keyPoint2);    

    //特征点描述,为下边的特征点匹配做准备    
    SurfDescriptorExtractor SurfDescriptor;    
    Mat imageDesc1,imageDesc2;    
    SurfDescriptor.compute(image1,keyPoint1,imageDesc1);    
    SurfDescriptor.compute(image2,keyPoint2,imageDesc2);      

    //获得匹配特征点,并提取最优配对     
    FlannBasedMatcher matcher;  
    vector matchePoints;    
    matcher.match(imageDesc1,imageDesc2,matchePoints,Mat());  
    sort(matchePoints.begin(),matchePoints.end()); //特征点排序    

    //获取排在前N个的最优匹配特征点  
    vector imagePoints1,imagePoints2;      
    for(int i=0;i<10;i++)  
    {         
        imagePoints1.push_back(keyPoint1[matchePoints[i].queryIdx].pt);       
        imagePoints2.push_back(keyPoint2[matchePoints[i].trainIdx].pt);       
    }  

    //获取图像1到图像2的投影映射矩阵 尺寸为3*3  
    Mat homo=findHomography(imagePoints1,imagePoints2,CV_RANSAC);  
    ////也可以使用getPerspectiveTransform方法获得透视变换矩阵,不过要求只能有4个点,效果稍差  
    //Mat   homo=getPerspectiveTransform(imagePoints1,imagePoints2);     
        cout<<"变换矩阵为:\n"<//输出映射矩阵  
    //图像配准  
    Mat imageTransform1,imageTransform2;  
    warpPerspective(image01,imageTransform1,homo,Size(image02.cols,image02.rows));    
    imshow("经过透视矩阵变换后",imageTransform1);  

    waitKey(1000);      
}  

void sift_pixel(char* src)
{
    //从文件中读入图像
    Mat img = imread(src);
    //如果读入图像失败
    if(img.empty())
        fprintf(stderr, "Can not load image %s\n", src);
    //显示图像
    imshow("image before", img);
    //sift特征检测
    SiftFeatureDetector  siftdtc;
    vectorkp1;

    siftdtc.detect(img,kp1);
    Mat outimg1;
    drawKeypoints(img,kp1,outimg1);
    imshow("image1 keypoints",outimg1);

    //此函数等待按键,按键盘任意键就返回
    waitKey();
}

注意:编译的时候,在整个工程属性需要设置成:配置类型->动态库dll,编译后在该工程下就会生成dll_sift的dll、lib等文件。在这里需要按照正常流程配置opencv,不过不能把opencv的dll路径加到环境变量中。
封装opencv的函数成dll,独立调用_第1张图片

2、在没opencv的电脑上解析dll_sift.dll

在完全没有opencv的电脑上,新建一个工程test_sift,将第一步中生成的dll_sift.dll文件拷贝到该工程目录下,添加一个cpp文件,代码如下:

#include
#include
using namespace std;

//所调用dll文件的存放路径  
const char* DllName="dll_sift.dll";  
//获取dll句柄  
HMODULE dll_sift=LoadLibraryA(DllName);  

//类型声明  
typedef void(*sift)(char*, char*);  
typedef void(*sift_pixel)(char*);  

//获取函数地址 ,解析dll获取函数 
sift sift0 = sift(GetProcAddress(dll_sift, "sift"));  
sift_pixel sift1 = sift_pixel(GetProcAddress(dll_sift, "sift_pixel"));  


void main()
{
    // 输入图像路径
    char* path1 = "22.jpg";
    char* path2 = "112.jpg";
    sift0(path1,path2);
    sift1(path2);
}

运行该工程,会出现,
封装opencv的函数成dll,独立调用_第2张图片
原因: 在上面的dll_sift.dll中相关的函数还调用了其他的opencv的dll但是这部分dll在该工程下没有,因此,需要将dll_sift.dll中相关函数调用需要用到的opencv的dll拷贝到该工程目录下。

3、获取dll_sift.dll中相关函数调用到的opencv的dll

问题在这里,因为opencv中的各种函数调用错综复杂,互相调用的很多,怎么知道自己调用的这个sift的相关函数调用哪些dll,如果将opencv的全部的dll都拷贝,太多了。方法如下:将生成dll的工程dll_sift的属性设置成:配置类型->应用程序(.exe),同时在dll_sift.cpp 文件中写一个空的main函数,再编译生成exe文件,在这个过程中一直会提示应用程序差opencvxxxx.dll,在opencv库目录下找到对应的dll,拷贝出来放在该工程下,再编译,再提示差dll,再拷贝相关的dll,知道exe可以编译成功
封装opencv的函数成dll,独立调用_第3张图片
这些所有的拷贝出来的opencv的dll就是dll_sift.dll所有的需要的opencv的dll文件,再将这些dll文件拷贝到test_sift工程目录下即可。
最后根据提示显示差这些dll:
封装opencv的函数成dll,独立调用_第4张图片
将这些dll全部拷贝到test_sift工程下,再次运行:
封装opencv的函数成dll,独立调用_第5张图片
运行成功。这样后面需要的时候,直接将上述的opencv的dll以及dll_sift.dll拷贝到没有opencv的电脑上就可以实现对opencv的sift工程的调用。

后记

在opencv的配置中一般需要配置h文件、以及lib文件,但是这些文件都只是在编译中有用的,真正运行的时候需要调用的是dll文件,一般在配置opencv的都是将opencv中dll的路径写到path变量中,这样写的程序运行的时候会从环境变量中找到dll的路径并调用。所以只要知道真正需要运行所需要的opencv的dll并将其拷贝,就可以将opencv的应用程序在没有opencv 的系统上运行。

例程代码下载:

(http://download.csdn.net/download/u012273127/10143339)

你可能感兴趣的:(OPENCV,C++)