1. 程式人生 > >vs2015+opencv生成DLL並分別靜態和動態呼叫

vs2015+opencv生成DLL並分別靜態和動態呼叫

網路上關於vs生成dll的教程很多,解決方案繁雜,令人眼花繚亂,踩坑後推薦幾篇不錯的教程,親自測試可以通過的,我的除錯環境是vs2015 enterprise版+win10+opencv3.4.1。

教程1:最簡單的DLL生成與呼叫教程:作者採用了宣告類進行打包的方法來呼叫。

教程2:進階的DLL生成與呼叫教程,包含了opencv第三方lib和dll的呼叫與打包,生成的DLL可獨立於opencv環境執行。採用的是打包函式的方法,本人推薦這種方法,比較簡單易懂。

教程3:教程2中採用了靜態呼叫方法,且沒有給出多個函式的匯出宣告,於是我參考教程3完成了多函式匯出宣告與動態呼叫。

1.需求分析:

將一個基於opecv的影象超解析度程式打包成DLL,並測試。介面傳入的引數是Mat格式的影象,結果是imshow超解析度後的影象。

2.新建DLL工程

1. 建立無匯出符號的dll空專案; 


2. 然後就是將之前寫的函式程式碼複製到原始檔中的Bleed.cpp中,其它兩個cpp不要管。


複製完畢後,點開Bleed.cpp然後對要呼叫的函式前面加上__declspec(dllexport),如圖中所示:

int Bleeding(Mat srcImage) 變為__declspec(dllexport) int Bleeding(Mat srcImage)

作為匯出函式宣告。


3. 建立原始檔Source.def 

新增->新建->visual C++ ->模組定義檔案(.def) 

LIBRARY "Bleed"
EXPORTS
	Bleeding

- 在此檔案第一行引號中填你的專案名稱即可,EXPORTS下面列出要生成的函式名稱,若有多個匯出函式,則 格式:“名稱 @序號”)如:

LIBRARY "DLLGenerator"
EXPORTS
    Add @1
    Mul @2
這個例子匯出了Add和Mul兩個函式。

4. 然後在右鍵點生成解決方案。


在工程目錄下會發現生成的Bleed.dll和Bleed.lib檔案。


3.靜態呼叫DLL

DLL的呼叫可分為動態呼叫和靜態呼叫兩種,靜態呼叫以來.h,.lib以及.dll檔案,而動態呼叫僅需要dll檔案。先講下如何靜態呼叫DLL:

1. 在專案管理器裡,右鍵單擊解決方案,新增/新建專案C++/Win32控制檯應用程式,命名。選擇沒有預編譯頭。


2. 新增測試程式碼

在原始檔的test_Bleed.cpp新增以下內容

   // test_Bleed.cpp : 定義控制檯應用程式的入口點。
    //
    #include "stdafx.h"
    #include <stdio.h>    
    #include <iostream>  
    using namespace std;

    #pragma comment(lib, "Bleed.lib")        //呼叫dll檔案時候必須用到的    
    void Bleeding();          //對剛才寫好的處理函式進行宣告    
    //主函式    
    int main()
    {
        Bleeding();
        return 0;
    }
3. 生成解決方案,現在肯定是很多錯誤; 
4.將dll和lib檔案拷貝到debug資料夾下,與exe檔案是同一個資料夾,另外,之前dll引用的檔案也都複製到現在這個專案的與cpp同一資料夾下; 
5.右鍵專案名字
選擇屬性,->配置屬性->VC++目錄->常規-庫目錄,選擇你放置了lib的debug資料夾。 
->配置屬性->連結器-輸入-附加依賴項-編輯加入lib的檔名(全名包含字尾)-確認 
6.生成,執行即可

4.動態呼叫DLL

1. 刪掉靜態呼叫時配置的lib和連結器選線: 刪除:右鍵專案名字選擇屬性,->配置屬性->VC++目錄->常規-庫目錄,選擇你放置了lib的debug資料夾。 
 刪除:配置屬性->連結器-輸入-附加依賴項-編輯加入lib的檔名(全名包含字尾)-確認 
2. 在原始檔中test_dll.cpp新增以下程式碼:
#include "stdafx.h"
#include <stdio.h>    
#include <iostream>  
#include <Windows.h> 
#include <opencv2/imgproc/imgproc.hpp>  
#include <opencv2/core/core.hpp>  
#include <opencv2/highgui/highgui.hpp>  
 
using namespace cv;
using namespace std;

typedef int(*Dllfun)(Mat);
int _tmain(int argc, _TCHAR* argv[])
{
	Dllfun Bleed;
	HINSTANCE hInst = LoadLibrary(L"Bleed.dll");
	if (!hInst)
	{
		printf("載入dll失敗!\n");
	}
	Bleed = (Dllfun)GetProcAddress(hInst, "Bleeding");
	
	Mat srcImage = imread("E:\\JMCpp\\000024.jpg");
	if (!srcImage.data)
		return -1;
	Bleed(srcImage);
	::FreeLibrary(hInst);
	return 0;
}  
因為測試程式使用了opencv的imread函式,所以#include了opencv的庫,若不適用imread,DLL可以脫離opencv使用。