//------------------------------------------------------------------------- // VideoCAPture by Gerox(c) 1998 for MATLAB // Clipboard Version for Video Capture by Gerox(c) 1998 // Frame memory Version for Video Capture by Gerox(c) 1998 // Support 16 bit color mode 1998.9.5 Kazuyuki Kobayashi // 1998.9.6 For IBM Smart Video Capture Card Kazuyuki Kobayashi // 1998.9.7 To fix for other video card (Canopus) // 1998.9.8 floating point bug fixed. // 1999.1.2 Support USB camera by using Clipboard mode. // 1999.8.17 To add capability for select video card for I/O DATA USB camera. // 2002.10.11 Convert from C++ version to C version & bug fix for windows 2000 // 2002.10.13 bug fix for windows 98 and matlab 5.3 // 2002.11.12 add pragma directive to avoid additional compile option // 2002.12.26 display [direct copy/compressed] mode // E-mail: ikko@k.hosei.ac.jp // http://www.gerox.com //------------------------------------------------------------------------- #if 0 In orde to compile mex vcapg.c MATLAB SAMPLE SCRIPT for VCAPG.DLL % VideoCature by Gerox(c) sample program % 1998.9.6 Kazuyuki Kobayashi % NOTE: % The 'clear' command cannot remove vcapg from MATLAB memory. % In order to remove vcapg, % you have to use 'clear all' or 'clear mex' or clear vcapg; % You can also use normal mode with captured window % Example map=vcapg; % You can also use fast mode with no captured window % Example map=vcapg('fast'); % NOTE: fast/normal mode command only accept first time. % if you want to change mode, you have to use 'clear vcapg'; % After that you can specify desired mode. % In order to support undocumented compressed image mode for USB camera, % we use clipboard transfer technique. % However this is not efficient, we recommend to use bitmap supported % video-capture board.(about two-times slower!) mapp=vcapg('fast'); aaa=image(mapp); drawnow; cputime set(aaa,'Erasemode','xor'); set(gca,'drawmode','fast'); % Since MATLAB Ver 5.2 support undocumented property doublebuffer set(gcf,'doublebuffer','on'); % set fast as much as possible ff=zeros(1,30); [x,y,z]=size(mapp); %mmm=uint8(zeros(x,y,z,30)); for ii=1:30 mapp=vcapg; %mapp = uint8((double(mapp) > 128)*255); %hhh=abs(diff(double(mapp))); %mapp=uint8(hhh/max(max(max(hhh)))*255); set(aaa,'cdata',mapp); drawnow; %mmm(:,:,:,ii) = mapp; ff(ii)=cputime; end #endif //------------------------------------------------------------------------- #define STRICT #pragma comment(lib, "user32.lib") #pragma comment(lib, "gdi32.lib") #pragma comment(lib, "shell32.lib") #pragma comment(lib, "vfw32.lib") #include #include #include #include #include "mex.h" #define WM_USER_NOTIFYICON WM_USER #define MAXVIDDRIVERS 10 #define print mexPrintf("%s %d\n",__FILE__,__LINE__) //------------------------------------------------------------------------- typedef struct{ unsigned int biSize; int biWidth; int biHeight; unsigned short biPlanes; unsigned short biBitCount; unsigned int biCompression; unsigned int biSizeImage; int biXPelsPerMeter; int biYPelsPerMeter; unsigned int biClrUsed; unsigned int biClrImportant; } SBITMAPINFO; typedef struct{ unsigned char rgbBlue; unsigned char rgbGreen; unsigned char rgbRed; unsigned char rgbReserved; }SRGBQUAD; //--------------------------------------------------------------------- // Global Variables // #define FNWCALLBACK FAR PASCAL _loadds static int initialized = 0; static long imagelength = 0; static long colorlength = 0; // Global static HWND ghWndCap = NULL; static HWND ghWndMain = NULL; static FARPROC fpFrameCallback = NULL; static HICON hIcontaskbar = NULL; static unsigned char *imageinfo = NULL; static CRITICAL_SECTION Cs; static SBITMAPINFO bi; static WNDCLASS wc; static NOTIFYICONDATA nIcon; static CHAR achDeviceName[80]; static CHAR achDeviceVersion[100]; static const TCHAR gachAppName[] = TEXT("VideoCapture by Gerox(c)"); static HINSTANCE hInstance; // Local pointer for MATLAB return; static unsigned char *bmpmap = NULL; unsigned short readu2(unsigned char *f,long *cnt){ register unsigned short ret; ret = ((unsigned short)f[(*cnt)++] & 0xff); ret |= (((unsigned short)f[(*cnt)++] & 0xff) << 8); return ret; } int read4(unsigned char *f,long *cnt){ register int ret; ret = ((int)f[(*cnt)++] & 0xff); ret |= (((int)f[(*cnt)++] & 0xff) << 8); ret |= (((int)f[(*cnt)++] & 0xff) << 16); ret |= (((int)f[(*cnt)++] & 0xff) << 24); return ret; } unsigned int readu4(unsigned char *f,long *cnt){ register unsigned int ret; ret = ((unsigned int)f[(*cnt)++] & 0xff); ret |= (((unsigned int)f[(*cnt)++] & 0xff) << 8); ret |= (((unsigned int)f[(*cnt)++] & 0xff) << 16); ret |= (((unsigned int)f[(*cnt)++] & 0xff) << 24); return ret; } LRESULT FNWCALLBACK FrameCallbackProc(HWND hWnd,LPVIDEOHDR lpVHdr){ long colorinfo = capGetVideoFormat(ghWndCap,NULL,0); if(imagelength != (long)lpVHdr->dwBufferLength || colorinfo != colorlength) { long count = 0; EnterCriticalSection(&Cs); colorlength = colorinfo; imagelength = lpVHdr->dwBufferLength; if(imageinfo != NULL) mxFree(imageinfo); imageinfo = (unsigned char*) mxCalloc(colorlength + imagelength,sizeof(unsigned char)); mexMakeMemoryPersistent(imageinfo); capGetVideoFormat(ghWndCap,imageinfo,colorlength); bi.biSize = readu4(imageinfo,&count); bi.biWidth = read4(imageinfo,&count); bi.biHeight = read4(imageinfo,&count); count += 2; bi.biBitCount = readu2(imageinfo,&count); bi.biCompression = readu4(imageinfo,&count); count +=12; bi.biClrUsed = readu4(imageinfo,&count); memcpy((imageinfo+colorlength),lpVHdr->lpData,imagelength); LeaveCriticalSection(&Cs); return (LRESULT) TRUE; } else { EnterCriticalSection(&Cs); memcpy((imageinfo+colorlength),lpVHdr->lpData,imagelength); LeaveCriticalSection(&Cs); return (LRESULT) TRUE; } return (LRESULT) TRUE; } void cLeanup(void) { if(initialized == 1) { mxFree(imageinfo); DeleteCriticalSection(&Cs); capSetCallbackOnError(ghWndCap,NULL); if(fpFrameCallback) { FreeProcInstance(fpFrameCallback); fpFrameCallback = NULL; } capSetCallbackOnStatus(ghWndCap,NULL); capSetCallbackOnYield(ghWndCap,NULL); capDriverDisconnect(ghWndCap); DestroyWindow(ghWndCap); DestroyWindow(ghWndMain); UnregisterClass(gachAppName,hInstance); initialized = 0; mexPrintf("----------------------------------------------------\n"); mexPrintf("VCAPG is safely removed from MATLAB memory. \n"); mexPrintf("Video CAPture for MATLAB by Gerox(c) Build %s\n",__DATE__); mexPrintf("----------------------------------------------------\n"); } else { mexPrintf("----------------------------------------------------\n"); mexPrintf("Video CAPture for MATLAB by Gerox(c) Build %s\n",__DATE__); mexPrintf("----------------------------------------------------\n"); } } static void resetwinsize(void) { CAPSTATUS gCapStatus; capGetStatus(ghWndCap,&gCapStatus,sizeof(CAPSTATUS)); SetWindowPos(ghWndCap,NULL,CW_USEDEFAULT,CW_USEDEFAULT, gCapStatus.uiImageWidth, gCapStatus.uiImageHeight,SWP_NOZORDER | SWP_NOMOVE); SetWindowPos(ghWndMain,NULL,CW_USEDEFAULT,CW_USEDEFAULT, gCapStatus.uiImageWidth + 8,gCapStatus.uiImageHeight + 26, SWP_NOZORDER | SWP_NOMOVE); } LONG FAR PASCAL MainWndProc(HWND hWnd,UINT Message,UINT wParam,LONG lParam) { switch (Message) { case WM_CREATE: nIcon.cbSize = sizeof(NOTIFYICONDATA); nIcon.uID = 1; nIcon.hWnd = hWnd; nIcon.uFlags = NIF_MESSAGE|NIF_ICON|NIF_TIP; nIcon.hIcon = hIcontaskbar; nIcon.uCallbackMessage = WM_USER_NOTIFYICON; strcpy(nIcon.szTip,"VideoCAPture by Gerox(c)"); Shell_NotifyIcon(NIM_ADD,&nIcon); break; case WM_USER_NOTIFYICON: if(lParam == WM_LBUTTONDOWN) { CAPDRIVERCAPS gCapDriverCaps ; capDriverGetCaps(ghWndCap,&gCapDriverCaps,sizeof(CAPDRIVERCAPS)); if (gCapDriverCaps.fHasDlgVideoFormat) { SetForegroundWindow(ghWndCap); capDlgVideoFormat(ghWndCap); SetActiveWindow(ghWndCap); resetwinsize(); } } break; case WM_DESTROY: Shell_NotifyIcon(NIM_DELETE,&nIcon); break; default: return DefWindowProc(hWnd,Message,wParam,lParam); } return 0L; } static void init(int preview,int initwIndex){ WORD wDriverCount = 0; int dwError = 0; int wIndex; long count = 0; hInstance =(HINSTANCE)GetWindowLong(HWND_DESKTOP,GWL_HINSTANCE); InitializeCriticalSection(&Cs); mexAtExit(cLeanup); wc.lpszClassName = gachAppName; wc.hInstance = hInstance; wc.lpfnWndProc = MainWndProc; wc.hCursor = LoadCursor(NULL,IDC_ARROW); wc.hIcon = LoadIcon(NULL,IDI_WINLOGO); wc.lpszMenuName = TEXT("VCAPG"); wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wc.style = CS_HREDRAW | CS_VREDRAW; wc.cbClsExtra = 0; wc.cbWndExtra = 0; hIcontaskbar = wc.hIcon; RegisterClass(&wc); // Create Application's Main window ghWndMain = CreateWindowEx(0,gachAppName,TEXT("VideoCAPture Gerox(c)"), WS_CAPTION | WS_MINIMIZEBOX | WS_THICKFRAME | WS_OVERLAPPED, CW_USEDEFAULT,0,160,120,NULL,NULL,hInstance,NULL); if(preview == 1) ShowWindow(ghWndMain,1); else ShowWindow(ghWndMain,SW_HIDE); UpdateWindow(ghWndMain); ghWndCap = capCreateCaptureWindow((LPTSTR)TEXT("VideoCAPture Gerox(c)"), WS_CHILD | WS_VISIBLE,0,0,160,120,(HWND) ghWndMain,(int)0); fpFrameCallback=MakeProcInstance((FARPROC)FrameCallbackProc,hInstance); capSetCallbackOnFrame(ghWndCap,fpFrameCallback); if(initwIndex >= MAXVIDDRIVERS) { cLeanup(); mexPrintf("Please Check Video capture card\n"); mexPrintf("No video capture hardware detected.\n"); mexErrMsgTxt(" Gerox(c) 1998,1999,2002 \n"); } for (wIndex = initwIndex;wIndex < MAXVIDDRIVERS;wIndex++) { if (capGetDriverDescription(wIndex,(LPTSTR)achDeviceName, sizeof(achDeviceName)/ sizeof(TCHAR), (LPTSTR)achDeviceVersion,sizeof(achDeviceVersion)/sizeof(TCHAR))) { // Only if no other driver is already connected dwError = capDriverConnect(ghWndCap,wIndex); if(dwError == 0) continue; else break; } } if(dwError == 0) { cLeanup(); mexPrintf("Please Check Video Card\n"); mexPrintf("No video capture hardware detected.\n"); mexErrMsgTxt(" Gerox(c) 1998,2002 \n"); } capPreviewRate(ghWndCap,10); capOverlay(ghWndCap,TRUE); capPreview(ghWndCap,TRUE); colorlength = capGetVideoFormat(ghWndCap,NULL,0); imagelength = 0; if(NULL ==(imageinfo = (unsigned char*)mxCalloc(colorlength,sizeof(unsigned char)))) { cLeanup(); mexErrMsgTxt("Error imagelength"); } mexMakeMemoryPersistent(imageinfo); capGetVideoFormat(ghWndCap,imageinfo,colorlength); bi.biSize = readu4(imageinfo,&count); bi.biWidth = read4(imageinfo,&count); bi.biHeight = read4(imageinfo,&count); count += 2; bi.biBitCount = readu2(imageinfo,&count); bi.biCompression = readu4(imageinfo,&count); count +=12; bi.biClrUsed = readu4(imageinfo,&count); } static void UnCompress(int Width,int Height,unsigned short BitCount,unsigned int ClrUsed,unsigned int Size){ int dims; int palsize = 0; int bit = 1; long linesize; long count; SRGBQUAD pal[256]; SRGBQUAD* pal2; int i; unsigned char *data; int dimx; int x,y,col1,col2,col3; int dimoffset; int dimoffset2; if(BitCount <= 8) { bit = 8 / BitCount; palsize = 1 << (BitCount); if(ClrUsed != 0) palsize = ClrUsed; } linesize = (long)(Width / (8 / (double)BitCount)); if(linesize % 4) linesize = (long)(((linesize / 4) + 1) * 4); count = (long) Size; palsize <<= 2; memcpy(pal,(imageinfo+count),palsize); count += palsize; dimoffset = Width * Height; dimoffset2 = dimoffset << 1; switch(BitCount) { case 4: /* ----------------------------- */ for(y = Height - 1; y > -1; y--) { data = &imageinfo[count]; count += linesize; for(x = 0; x < Width; x += bit) { dimx = x /bit; col1 = data[dimx] >> 4; col2 = data[dimx] & 0x0f; dims = x * Height + y; pal2 = &pal[col1]; bmpmap[dims] = pal2->rgbRed; bmpmap[dims + dimoffset] = pal2->rgbGreen; bmpmap[dims + dimoffset2] = pal2->rgbBlue; dims += Height; pal2 = &pal[col2]; bmpmap[dims] = pal2->rgbRed; bmpmap[dims + dimoffset] = pal2->rgbGreen; bmpmap[dims + dimoffset2] = pal2->rgbBlue; } } break; case 8: /* ----------------------------- */ for(y = Height -1; y > -1; y--) { data = &imageinfo[count]; count += linesize; for(x = 0; x < Width; x += bit) { col1 = data[x]; dims = x * Height + y; pal2 = &pal[col1]; bmpmap[dims] = pal2->rgbRed; bmpmap[dims + dimoffset] = pal2->rgbGreen; bmpmap[dims + dimoffset2] = pal2->rgbBlue; } } break; case 1: /* ----------------------------- */ { const int c[] = {1,2,4,8,16,32,64,128}; for(y = Height - 1; y > -1; y--) { data = &imageinfo[count]; count += linesize; for(x = 0; x < Width; x += bit) { for(i = 0;i < 8; i++){ if((data[x / bit] & c[i]) == c[i]) col1 = 1; else col1 = 0; dims = (x + i) * Height + y; pal2 = &pal[col1]; bmpmap[dims] = pal2->rgbRed; bmpmap[dims + dimoffset] = pal2->rgbGreen; bmpmap[dims + dimoffset2] = pal2->rgbBlue; } } } } break; case 16: /* ----------------------------- */ for(y = Height - 1; y > -1; y--) { data = &imageinfo[count]; count += linesize; for(x = 0; x < Width; x += bit) { dimx = x << 1; col1 = (data[dimx] & 0x1f); col2 = ((data[dimx] >> 5) & 0x7) + ((data[dimx + 1] << 3) & 0x18); col3 = (data[dimx + 1] >> 2) & 0x1f; dims = x * Height + y; bmpmap[dims] = col3 << 3; bmpmap[dims + dimoffset] = col2 << 3; bmpmap[dims + dimoffset2] = col1 << 3; } } break; case 24: /* ----------------------------- */ for(y = Height - 1; y > -1; y--) { data = &imageinfo[count]; count += linesize; for(x = 0; x < Width; x += bit) { dimx = (x << 1) + x; col1 = data[dimx++]; col2 = data[dimx++]; col3 = data[dimx]; dims = x * Height + y; bmpmap[dims] = col3; bmpmap[dims + dimoffset] = col2; bmpmap[dims + dimoffset2] = col1; } } break; } } void mexFunction(int nlhs,mxArray *plhs[],int nrhs,const mxArray *prhs[]) { int dims[3]; /* Check for proper number of arguments */ _control87(MCW_EM,MCW_EM); if ((nrhs > 1) || (nlhs > 1)) { mexPrintf("imagearray=VCAPG(preview mode)\n"); mexPrintf("Example of fast capture mode\n"); mexPrintf("This allow to capture image without monitoring window\n"); mexPrintf("---------------------------------------\n"); mexPrintf("clear vcapg;vcapg('fast');image(vcapg);\n"); mexPrintf("---------------------------------------\n"); mexPrintf("Example of normal preview mode\n"); mexPrintf("---------------------------------------\n"); mexPrintf("clear vcapg;image(vcapg);\n"); mexPrintf("---------------------------------------\n"); mexPrintf("NOTE: if Preview mode is a scalar number, it become videocapture number which is determined by windows configuraion.\n"); mexPrintf("NOTE: Mode change parameter effects only at first time.\n"); mexPrintf("In order to change mode, please execute 'clear vcapg;'\n"); mexPrintf("\n"); mexPrintf("---------------------------------------\n"); mexPrintf("If you want to change capture resolution and/or color mode,\n"); mexPrintf("click the left bottom VCAPG notification icon. \n"); mexPrintf("Resolution: You may apply any resolution which is restricted by video capture board. \n"); mexPrintf("Video mode: Supported format is uncompressed BITMAP format with 1/4/8/16/24 bit color. \n"); mexPrintf("NOTE: If we detect compressed mode, \n"); mexPrintf(" we apply slower version of capture program \n"); mexPrintf(" which used clipboard transfer mode. \n"); mexPrintf(" So if you want to better performance,\n"); mexPrintf(" please use uncompressed BITMAP format. \n"); mexPrintf("Video CAPture for MATLAB(win 95/98/2000) by Gerox(c) %s\n",__DATE__); mexPrintf("Tips: In order to draw faster, please use set(gcf,'doublebuffer','on'); \n"); cLeanup(); mexErrMsgTxt("\n"); } if(initialized == 0) { // if argument is double then get initial value with display mode // else no display mode; // if no argument then with display mode if(nrhs == 1) { if((mxDOUBLE_CLASS == mxGetClassID(prhs[0])) && (mxGetN(prhs[0]) * mxGetM(prhs[0]) == 1) && (mxGetNumberOfDimensions(prhs[0]) == 2)) { init(1,(int)mxGetScalar(prhs[0])); } else init(0,0); } else init(1,0); initialized = 1; SendMessage(ghWndCap,WM_CAP_GRAB_FRAME_NOSTOP,0,0); if(bi.biCompression != 0) { SendMessage(ghWndCap,WM_CAP_EDIT_COPY,0,0); mexPrintf("Clipboard mode\n"); } else mexPrintf("DirectCopy mode\n"); SetActiveWindow(ghWndCap); while (imagelength == 0){ MSG msg; GetMessage(&msg,NULL,0,0); DispatchMessage(&msg); } resetwinsize(); } SendMessage(ghWndCap,WM_CAP_GRAB_FRAME_NOSTOP,0,0); if(bi.biCompression != 0) SendMessage(ghWndCap,WM_CAP_EDIT_COPY,0,0); /* Do the actual computations in a subroutine */ if(bi.biCompression == 0) { dims[0] = bi.biHeight; dims[1] = bi.biWidth; dims[2] = 3; plhs[0] = mxCreateNumericArray(3,dims,mxUINT8_CLASS,mxREAL); /* Assign pointers to the various parameters */ bmpmap = (unsigned char *)mxGetPr(plhs[0]); EnterCriticalSection(&Cs); UnCompress(bi.biWidth,bi.biHeight,bi.biBitCount,bi.biClrUsed,bi.biSize); LeaveCriticalSection(&Cs); } else { HANDLE dibmap; long count = 0; long leng; int biSize,biWidth,biHeight,biBitCount,biClrUsed; unsigned char *thbitmap; if(OpenClipboard(NULL) != TRUE) return; if(0==IsClipboardFormatAvailable(CF_DIB)) return; if(NULL == (dibmap = GetClipboardData(CF_DIB))) return; leng = GlobalSize(dibmap); thbitmap = (unsigned char*)GlobalLock(dibmap); EnterCriticalSection(&Cs); if(imageinfo != NULL) mxFree(imageinfo); imageinfo = (unsigned char*) mxCalloc(leng,sizeof(unsigned char)); mexMakeMemoryPersistent(imageinfo); memcpy(imageinfo,thbitmap,leng); GlobalUnlock(dibmap); CloseClipboard(); biSize=readu4(imageinfo,&count); biWidth=read4(imageinfo,&count); biHeight=read4(imageinfo,&count); count += 2; biBitCount = readu2(imageinfo,&count); count +=16; biClrUsed = readu4(imageinfo,&count); dims[0] = biHeight; dims[1] = biWidth; dims[2] = 3; plhs[0] = mxCreateNumericArray(3,dims,mxUINT8_CLASS,mxREAL); /* Assign pointers to the various parameters */ bmpmap = (unsigned char *)mxGetPr(plhs[0]); UnCompress(biWidth,biHeight,biBitCount,biClrUsed,biSize); LeaveCriticalSection(&Cs); } }