程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> VC >> 關於VC++ >> 利用window API實現matlab屏幕抓取函數

利用window API實現matlab屏幕抓取函數

編輯:關於VC++

摘要:結合如何用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功能。

  1. 上一頁:
  2. 下一頁:
欄目導航
Copyright © 程式師世界 All Rights Reserved