摘要:結合如何用window API實現matlab屏幕抓取函數,介紹了在matlab中如何利用matlab與C/C++的接口,調用操作系統API,擴展matlab功能。
引言
MATLAB 產品家族是美國 MathWorks公司開發的用於概念設計,算法開發,建模仿真,實時實現的理想的集成環境。由於其完整的專業體系和先進的設計 開發思路,使得 MATLAB 在多種領域都有廣闊的應用空間。
盡管MATLAB在科學研究以及工業技術開發方面有著極為廣泛的應用,但是它也不是萬能的。在某些場合下,MATLAB自身攜帶的函數及其組合並無法完全滿足用戶的要求,而必須通過調用操作系統的API函數來實現。MATLAB在設計時已經考慮到這點,為我們提供了mex命令,可用於將調用操作系統API函數的C程序編譯成DLL文件,也就是MEX文件,使之成為MATLAB的一個擴展函數。這樣,我們在MATLAB環境下編程時就可以直接調用該擴展函數,達到間接調用操作系統API函數的目的。本文將通過如何為MATLAB編寫屏幕抓取函數來演示上述過程。
MEX接口
MEX是MATLAB Executable的縮寫,也就是可以在MATLAB中執行。這是MATLAB和其他主要編程語言如C/C++,FORTRAN的接口。普通的C/C++或是FORTRAN源程序,只要加上一個特殊的接口函數,就能通過MATLAB裡的MEX命令編譯成一種特殊的動態鏈接庫函數,而這種函數可以在MATLAB環境下編程時直接調用,與MATLAB內嵌的函數一樣。這個特殊的接口函數相當於C程序中的main函數,是程序的入口,程序的執行就是從這個入口函數開始的。其原型為
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
其中,參數nlhs和nrhs為輸出和輸入變量的數目,參數plhs和prhs為輸出和輸入變量指針的指針,prhs是長度為nrhs的輸入變量的指針數組,plhs是長度為nlhs的輸出變量的指針數組。
利用window API實現matlab屏幕抓取函數
本質上就是利用C語言調用window API函數來實現屏幕抓取功能,同時,必須處理好C語言與matlab接口問題和C語言中數組存儲與matlab中數組存儲的轉化問題。
以下是C源程序,有詳細的注釋。
// matlab mex file to snap the screen
// compile to use>> mex screensnap.c user32.lib gdi32.lib
// usage:1, >>a=screensnap(0) %exclude the matlab window
// >>imshow(a);
// 2, >>a=screensnap(1); %include the matlab window
// >> imshow(a);
// designed by darnshong [email protected]
// 2005,12,18
#include <windows.h>
#include <string.h>
#include "mex.h"
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
int cx,cy,recnum;
int dims[3],i,j,k;
char *pchar,*mloc;
bool bshowmatlab;//抓屏時是否屏蔽matlab主窗口
HWND hwin,hactw;
HDC dc,memdc;
RECT rect;
HBITMAP hbitm,hold;
BITMAPINFOHEADER binfoh;
if(nrhs!=1) //對輸入參數進行檢驗
mexErrMsgTxt("Need 1 argument!\n");
if(!mxIsDouble(prhs[0]))
mexErrMsgTxt("The input argument must be a numeric!\n");
if(*(double*)(mxGetData(prhs[0]))==0)
bshowmatlab=false;
else
bshowmatlab=true;
hactw=GetForegroundWindow();//獲取matlab的窗口句柄
hwin=GetDesktopWindow();//獲取桌面窗口句柄
dc=GetWindowDC(hwin);//獲取桌面窗口DC
GetWindowRect(hwin,&rect);//獲取桌面窗口大小
cx=rect.right-rect.left;
cy=rect.bottom-rect.top;
mexPrintf("cx: %d cy: %d\n !",cx,cy);
memdc=CreateCompatibleDC(dc);//創建與桌面窗口DC相適應的內存DC
mexPrintf("Handles: %d %d %d\n !",hwin,dc,memdc);
hbitm=CreateCompatibleBitmap(dc,cx,cy);//創建相適應的位圖
if(hbitm==0)
mexErrMsgTxt("Fail to create a compatible bitmap!\n");
if (!(hold=SelectObject(memdc, hbitm))) //將新建的位圖選入內存DC中
mexErrMsgTxt("Compatible Bitmap Selection!\n");
// Hide the application window.
if(!bshowmatlab)
{
ShowWindow(hactw, SW_HIDE); //屏蔽matlab主窗口
Sleep(100);//延遲100ms,因為在屏蔽matlab主窗口的過程中不能抓屏
}
//Copy color data for the entire display into a
//bitmap that is selected into a compatible DC.
if (!BitBlt(memdc,0,0,cx,cy,dc,0,0,SRCCOPY)) //將桌面窗口DC拷貝到內存DC中
mexErrMsgTxt("Screen to Compat Blt Failed");
dims[0]=cy;//注意cx,cy的順序
dims[1]=cx;
dims[2]=3;
plhs[0]=mxCreateNumericArray(3,dims,mxUINT8_CLASS,mxREAL);
//創建輸出變量空間來傳遞圖像數據
//由於是彩色圖像,含RGB三分量,所以為三維數據
pchar=(char*)mxGetData(plhs[0]);
binfoh.biSize=sizeof(BITMAPINFOHEADER);
binfoh.biWidth=cx;
binfoh.biHeight=-cy;
binfoh.biPlanes=1;
binfoh.biBitCount=24;
binfoh.biCompression=BI_RGB;
binfoh.biSizeImage=0;
binfoh.biXPelsPerMeter=0;
binfoh.biYPelsPerMeter =0;
binfoh.biClrUsed=0;
binfoh.biClrImportant=0;
//配置位圖信息頭結構
mloc=(char*)mxMalloc(cx*cy*3);
//申請空間來存放圖像數據 recnum=GetDIBits(memdc,hbitm,0,cy,mloc,(BITMAPINFO*)&binfoh,DIB_RGB_COLORS);
//將圖像數據復制到mloc空間裡
mexPrintf("Copyed %d lines %d\n!",recnum,hbitm);
for(k=0;k<3;k++)
for(j=0;j<cy;j++)
for(i=0;i<cx;i++)
{
pchar[i*cy+j+k*cx*cy]=mloc[(j*cx+i)*3+2-k];
//由於matlab中數據存儲是先列後行的,與C程序中先行後列不一樣
//圖像數據在復制到輸出變量時必須進行適當的處理
}
mxFree(mloc);//釋放申請的內存空間
SelectObject(hbitm,hold);
DeleteDC(memdc);
ReleaseDC(hwin,dc);
DeleteObject(hbitm);
//完成之後進行必要的處理防止內存洩漏
if(!bshowmatlab)
ShowWindow(hactw, SW_SHOW);
//恢復matlab主窗口的顯示
}
上述程序中以mx,mex開頭的函數是matlab為方便mex文件的開發提供的函數,在mex.h文件中有聲明,matlab的幫助系統中有詳細的說明。
運行結果
將上述源程序保存為screensnap.c文件,在matlab命令窗口中運行:
mex screensnap.c user32.lib gdi32.lib
就可以產生一個screensnap.dll的動態鏈接庫文件,然後該文件所在的目錄加入matlab的搜索目錄中,在matlab命令窗口中運行如下命令:
dat=screensnap(0);%屏蔽matlab窗口,如果不屏蔽,可用dat=screensnap(1);
imshow(dat);%顯示圖像
則可以得到如下的結果
小結
通過以上示例可以看出,通過matlab與C的接口,我們可以充分利用C語言的優勢,根據自身的需要,利用C語言調用操作系統API進行編程,擴展和豐富matlab函數,更好的發揮matlab功能。