為什么會有把二者結合這個想法,主要是在接觸過這兩種工具后,發現它們對圖像處理有自己獨特的優勢,但也有自己的缺點,借助C++,opencv可以實現許多自己想實現的功能,但是在界面設計上得花另一番功夫,Labview的長處就在於它的界面設計簡單,控件拖拽所見即所得,與QT有點類似,當然QT的跨平台性是labview比不了的,可是labview在功能實現上的快速性和簡潔性也是較大的優勢,對labview稍微熟悉一點即可實現許多強大的功能。(當然,用什么都只是工具,主要是掌握方法與思想)
話不多說,進入正題:軟件版本Labview2015 64位英文版(要安裝VISION Acquisition Software組件) 和 Visual Studio 2015,注意生成的DLL要與Labview版本一致,都是64位才可以,否則會有其他的調用問題。
一、從Labview傳遞圖像數據到opencv中,經過圖像處理后又將處理結果返回到Labview顯示。(源圖片來源於Labview這端)
我這里有兩種圖像數據來源,一種是直接調用本地圖片,另一種是通過labview調用攝像頭傳輸視頻,可以做到實時的圖像傳輸和圖像處理。二者的區別只在Labview的設計上有稍許差別,Dll的內容是一致的。
既然DLL的內容一致,那就先介紹DLL的設計,前面幾篇中有講到VS如何創建DLL,可以翻看前面的內容,這里是調用軟件發生改變,不再是由VS自己調用,而是通過Labview來調用,步驟差別不大。
dll.h頭文件的定義如下:
#pragma once #include<iostream> #ifdef DLL_IMPLEMENT #define DLL_API _declspec(dllimport) #else #define DLL_API _declspec(dllexport) #endif extern "C" DLL_API void add2(int rows, int cols, unsigned __int8 *data); extern "C" DLL_API int ImgdatatoLabview(unsigned __int8 *imgdata); extern "C" DLL_API int getimagesize(int* rows, int* cols);
void add2(int rows, int cols, unsigned __int8 *data)是接收從labview傳來的數據進行圖像處理,注意參數類型,unsigned __int8 *data是指針類形,由於opencv中的圖片數據類型是Mat型,而Labview里面沒有Mat類型,所以要通過指針/數組來實現數據的傳遞。
下面是對圖像處理函數主體,完成的是一個調用opencv里的Canny邊緣提取函數。可以看到將image_src與關聯到指針的首地址,經過圖像處理后,最后的結果又返回到了image_src上,所以即便該函數沒有返回值,也是能實現圖像經過處理后傳回到Labview。
_declspec(dllexport) extern void add2(int rows, int cols, unsigned __int8 *data)//接收labview傳過來的圖像數據進行處理,圖片來源於labview的采集 { Mat image_src(rows, cols, CV_8U, &data[0]); /* Insert code here */ Mat temp; boxFilter(image_src, temp, -1, Size(5, 5)); Canny(temp, image_src, 150, 100, 3); }
Labview的設計
1、源圖像來源於本地圖片文件,Labview前面板可看到一下效果,在運行前先選擇文件目錄即可。
后面板邏輯:調用動態鏈接庫控件的位置在Connectivity->Libraries & Executables->Call Library Function Node
調用DLL參數設置,尤其注意指針data的數據類型為Array,Dimention為2
2、源圖像來源於usb攝像頭,這種方式需要安裝NI VISION Acquisition組件,也就是下圖所示的控件
前面板如下所示,圖一是攝像頭原圖,圖二是灰度圖,圖三是從opencv經過Canny邊緣檢測后返回的結果圖
后面板邏輯如下:這里包括了兩個沒講的DLL,可以先跳過這看完另外兩個DLL的解釋
二、從opencv傳遞圖像到Labview,即源圖像來源於opencv(本地文件或者調用攝像頭都可以)
其實前面的功能也已經實現了將處理好的圖像返回到labview顯示,這里只是再更直觀的體現一下圖片來源於opencv
這里就涉及到另外兩個DLL的使用一個是getimagesize獲取圖像文件大小的(獲取行列數才可以在labview里初始化數組的大小),另一個是 ImgdatatoLabview實現圖像的處理和傳遞(其實和第一個DLL功能類似,只是圖像大小需要通過另一個DLL獲得)
getimagesize功能代碼實現:可以看到獲得的圖像來源opencv調用本地文件
_declspec(dllexport) extern int getimagesize(int* rows, int* cols) { Mat ImgSrc = imread("E:\\study\\VS2015\\practice\\shumaguang\\shumaguang\\30.jpg");//read the image; *rows = ImgSrc.rows; *cols = ImgSrc.cols; return 0; }
代碼其實很簡單,只是需要注意從opencv獲取的行列信息要以指針的形式傳出,所以看到函數的參數都是指針。
所以在labview調用該DLL的參數設置上也要注意數據類型,如下圖所示
ImgdatatoLabview功能代碼實現:將原圖由RGB轉換為GRAY類型傳遞到Labview
_declspec(dllexport) extern int ImgdatatoLabview(int rows,int cols,unsigned __int8 *imgdata) { Mat ImgSrc = imread("E:\\study\\VS2015\\practice\\shumaguang\\shumaguang\\30.jpg");//read the image; Mat img(rows, cols, CV_8U, &imgdata[0]); cvtColor(ImgSrc, img, CV_BGR2GRAY); return 0; }
代碼也比較簡單:
參數rows和cols就是接收來自getimagesize函數的返回值,而*imgdata指針關聯到圖片,和第一個DLL功能基本一致
同樣注意該指針參數在Labview的設置 二維數組
Labview最后的功能實現,第四張圖片就是得到的灰度圖片,前面板如下所示,后面板和第一部分里的一樣,就不再貼圖了。
有心人可以發現這里不管是從Labview傳輸圖片到opencv還是從opencv傳輸到Labview,這里的圖片傳輸的都是灰度圖像,這是為什么,直接改變數組指針的類型可以實現彩色圖像的傳輸嗎?這個我也沒測試過,下一篇介紹如何實現彩色圖像的傳輸。