您當前的位置:首頁 > 繪畫

為基於OpenCV的影象處理程式編寫介面—關於QTMFCCSharp的選擇以及GOCW的介紹

作者:由 禾路 發表于 繪畫時間:2018-10-06

基於OpenCV編寫影象處理專案,除了演算法以外,比較重要一個問題就是介面設計問題。對於c++語系的程式設計師來說,一般來說有QT/MFC兩種考慮。QT的確功能強大,特別是QML編寫android介面很有一套(

https://www。

cnblogs。com/jsxyhelu/p/

8286476。html

),在樹莓派上進行設計也很方便(

https://www。

cnblogs。com/jsxyhelu/p/

7839062。html

);但是使用QT的一個現實問題就是和現有平臺的結合,比如客戶需要將結果匯出到excel中,使用QT就比較彆扭(當然不是說不可以)。所以現在我一般這樣來做:對於Android和PI,或者需要在Linux上執行的專案,使用QT編寫介面,呼叫Opencv函式;對於需要在windows上執行的專案,使用MFC編寫介面,直接就可以引用OpenCV。

有人會吐槽MFC使用起來非常麻煩,這點我非常同意。但MFC經過這麼多年的發展,今日仍有活力,並且短時間內不會消失。因為相比較其他一些所見即所得的語言和環境來說(QT/Csharp),mfc的訊息對映機制和座標體系等,的確有它的優勢,對於影象處理程式來說尤其如此;加以積累,能夠快速做出很多專業的東西;近期出現的ribbon介面也為mfc加分不少(

https://www。

cnblogs。com/jsxyhelu/p/

9209052。html

選擇了MFC這個方向,思考影象處理程式問題,一般來說分為“處理影象”和“處理影片”兩類:對於影象處理來說,我提供的GOPaint框架(

https://www。

cnblogs。com/jsxyhelu/p/

6440910。html

)能夠提供一個基本的靜態影象處理框架;而GOMFCTemplate2(

https://www。

cnblogs。com/jsxyhelu/p/

GOMFCTemplate2。html

)則適合用來處理影片。這兩種都分別成功運用於多種影片處理專案中。

但是這裡我想更進一步:希望能夠用Csharp編寫介面,因為它更好用;但是又不想引入EmguCV類似的庫,因為裡面很多東西不是我需要的。那麼最直接的方法就是使用Csharp呼叫基於Opencv編寫的類庫檔案(Dll)的,我取名叫做GreenOpenCsharpWarper(GOCW)

經過比較長時間的探索研究,目前的GOCW已經可以直接以函式的形式在記憶體中傳遞bitmap和Mat物件,達到了函式級別的應用。因為這裡涉及到託管程式碼編寫,也就是CLR程式編寫,所以有比較複雜的地方;為了展現GOCW的優良特性,我編寫實現GOGPY專案,也就是一個“Csharp編寫介面,OpenCV實現演算法的實時影片處理程式”,相關細節都包含其中。之所以叫“GPY”,是採集硬體這塊,我採用了成像質量較好的高拍儀裝置(GaoPaiYi)。

為基於OpenCV的影象處理程式編寫介面—關於QTMFCCSharp的選擇以及GOCW的介紹

為基於OpenCV的影象處理程式編寫介面—關於QTMFCCSharp的選擇以及GOCW的介紹

這裡簡單將最核心內容進行講解。GOCW的核心問題,無非就是基於CLR之上的兩個方向的資料流轉換。核心函式為

Bitmap^ GOClrClass::testMethod(cli::array<

unsigned

char

>^ pCBuf1)

{

pin_ptr p1 = &pCBuf1[0];

unsigned

char

* pby1 = p1;

cv::Mat img_data1(pCBuf1->Length,1,CV_8U,pby1);

cv::Mat img_object = cv::imdecode(img_data1,IMREAD_UNCHANGED);//獲得資料到img_object中去

//////////////////////////////////處理過程///////////////////////////////////////

cvtColor(img_object,img_object,40);

/////////////////////////////////////////////////////////////////////////////////

Bitmap^ bb = MatToBitmap(img_object);

if

(!img_object。data)

return

nullptr;

std::vector buf;

cv::imencode(”。jpg“, img_object, buf);

return

bb;

}

以及

System::Drawing::Bitmap^ MatToBitmap(

const

cv::Mat& img)

{

if

(img。type() != CV_8UC3)

{

throw

gcnew NotSupportedException(”Only images of type CV_8UC3 are supported for conversion to Bitmap“);

}

//create the bitmap and get the pointer to the data

PixelFormat fmt(PixelFormat::Format24bppRgb);

Bitmap ^bmpimg = gcnew Bitmap(img。cols, img。rows, fmt);

BitmapData ^data = bmpimg->LockBits(System::Drawing::Rectangle(0, 0, img。cols, img。rows), ImageLockMode::WriteOnly, fmt);

//byte *dstData = reinterpret_cast(data->Scan0。ToPointer());

Byte *dstData =

reinterpret_cast

(data->Scan0。ToPointer());

unsigned

char

*srcData = img。data;

for

int

row = 0; row < data->Height; ++row)

{

memcpy(

reinterpret_cast

<

void

*>(&dstData[row*data->Stride]),

reinterpret_cast

<

void

*>(&srcData[row*img。step]), img。cols*img。channels());

}

bmpimg->UnlockBits(data);

return

bmpimg;

}

而在chsarp中,直接

Bitmap b =

new

Bitmap(cam。Width, cam。Height, cam。Stride, PixelFormat。Format24bppRgb, m_ip);

// If the image is upsidedown

b。RotateFlip(RotateFlipType。RotateNoneFlipY);

srcImage = b;

if

(picPreview。Image != null)

picPreview。Image。Dispose();

//呼叫clr+opencv影象處理模組

MemoryStream ms =

new

MemoryStream();

b。Save(ms, System。Drawing。Imaging。ImageFormat。Jpeg);

byte[] bytes = ms。GetBuffer();

Bitmap bitmap = client。testMethod(bytes);

就可以呼叫,並且獲得結果。

以下內容為2017年更新的內容,適當參考:

一、CLR編寫的DLL部分

1、按照正常方法引入Opencv;

2、提供介面函式,進行影象處理(這裡只是實現了cvtColor,實際過程中可以用自己編寫的複雜函式)

String^ Class1::Method(cli::array<

unsigned

char

>^ pCBuf1)

{

pin_ptr p1 = &pCBuf1[0];

unsigned

char

* pby1 = p1;

cv::Mat img_data1(pCBuf1->Length,1,CV_8U,pby1);

cv::Mat img_object = cv::imdecode(img_data1,IMREAD_UNCHANGED);

//////////////////////////////////處理過程/////////

cvtColor(img_object,img_object,40);

/////////////////////////////////////////////////////////////////////////////////

if

(!img_object。data)

return

nullptr;

//獲得目錄,儲存檔案

cv::imwrite(”c:/Method。jpg“,img_object);

return

”c:/Method。jpg“;

}

String^ Class1::Method2(cli::array<

unsigned

char

>^ pCBuf1)

{

pin_ptr p1 = &pCBuf1[0];

unsigned

char

* pby1 = p1;

cv::Mat img_data1(pCBuf1->Length,1,CV_8U,pby1);

cv::Mat img_object = cv::imdecode(img_data1,IMREAD_UNCHANGED);

//////////////////////////////////處理過程///////////////////////

cvtColor(img_object,img_object,6);

/////////////////////////////////////////////////////////////////////////////////

if

(!img_object。data)

return

nullptr;

//獲得目錄,儲存檔案

cv::imwrite(”c:/Method2。jpg“,img_object);

return

”c:/Method2。jpg“;

}

二、Winform呼叫介面部分

(TIP:不僅可以用Winform呼叫,

http://

asp。net/webservice

都是可以呼叫的)

1、直接引用clr dll

為基於OpenCV的影象處理程式編寫介面—關於QTMFCCSharp的選擇以及GOCW的介紹

2、編寫helper檔案(應該也可以叫做 warpper),透過外部IO的方法獲取clr dll的檔案

class

GOCsharpHelper

{

Class1 client =

new

Class1();

string strResult1 = null;

string strResult2 = null;

//輸入引數是string或bitmap

public

Bitmap ImageProcess(string ImagePath){

Image ImageTemp = Bitmap。FromFile(ImagePath);

return

ImageProcess(ImageTemp);

}

//輸出結果是bitmap

public

Bitmap ImageProcess(Image image)

{

MemoryStream ms =

new

MemoryStream();

image。Save(ms, System。Drawing。Imaging。ImageFormat。Jpeg);

byte[] bytes = ms。GetBuffer();

strResult1 = client。Method(bytes);

Image ImageResult = Bitmap。FromFile(strResult1);

return

(Bitmap)ImageResult;

}

public

Bitmap ImageProcess2(string ImagePath)

{

Image ImageTemp = Bitmap。FromFile(ImagePath);

return

ImageProcess2(ImageTemp);

}

//輸出結果是bitmap

public

Bitmap ImageProcess2(Image image)

{

MemoryStream ms =

new

MemoryStream();

image。Save(ms, System。Drawing。Imaging。ImageFormat。Jpeg);

byte[] bytes = ms。GetBuffer();

strResult2 = client。Method2(bytes);

Image ImageResult = Bitmap。FromFile(strResult2);

return

(Bitmap)ImageResult;

}

public

void

Clear()

{

if

(File。Exists(strResult1))

File。Delete(strResult1);

if

(File。Exists(strResult2))

File。Delete(strResult2);

}

}

3、使用例子(注意控制元件的dispose):

private

void

button2_Click(object sender, EventArgs e)

{

if

(pictureBox1。Image != null)

pictureBox1。Image。Dispose();

if

(pictureBox2。Image != null)

pictureBox2。Image。Dispose();

Image image1 = gocsharphelper。ImageProcess(” E:/sandbox/logo。jpg“);

pictureBox1。Image = image1;

Image image2 = gocsharphelper。ImageProcess2(”E:/sandbox/lena。jpg“);

pictureBox2。Image = image2;

}

三、解釋說明

使用外部I/O不僅僅是權宜之計,實際上Opencv的Decode使用的就是外部I/O。就目前研究的水平來說,這是最穩定的。

目前搭建成功的框架已經能夠完成“csharp呼叫opencv的”目標,並且在除錯、引數傳遞方面都很強。

如果是處理靜態圖片,已經夠用。

四、殺手程式

GOImageResearch:

使用這種方法編寫的影象處理預分析程式。

為基於OpenCV的影象處理程式編寫介面—關於QTMFCCSharp的選擇以及GOCW的介紹

標簽: img  object  Image  bitmap  CV