// AcquireIMAQ_Native.cpp // // This is the Native C code that is called by ImageJ to capture an image // from a National Instruments Image Acquisition (IMAQ) board. This code // is currently set to capture images from a Hamamatsu Orca 12-bit CCD camera // (model C4742-95). Use this code as a basis for creating your image // acquisition interface for ImageJ. // // NOTE: This code is based somewhat on the National Instruments // "HLGrab.c" sample. // // Author: Jeffrey Kuhn // The University of Texas at Austin // jkuhn@ccwf.cc.utexas.edu // ///////////////////////////////////////////////////////////////////////////// #include #include #include #include // Java native interface #define _NIWIN #include // National Instruments IMAQ stuff #include "AcquireIMAQ_.h" // javah gernerated header from AcquireIMAQ_.java //*************************************************************************** // CONSTANTS //*************************************************************************** // // Program behavior constants // #define GRAB_ON_STARTUP TRUE // start grabbing immediately when the window is created? //#define TEST_ACQUISITION // do we want to test as an application instead of a DLL? // Normally, this definition is passed in by the Makefile // // Hamamatsu Camera Paramters // // NOTE: imgPlot seems to be limited to 1024 pixels wide, so we set this as the maximum size #define MAX_CAPTURE_WIDTH 1024 // maximum camera image size #define MAX_CAPTURE_HEIGHT 1024 // maximum camera image size #define MAX_EXPOSURE 1039 // maximum electronic shutter exposure time // // Window and control placement constants // #define CONTROL_WIDTH 90 // default control width #define CONTROL_HEIGHT 20 // default control height #define BUTTON_HEIGHT 24 // default button height #define BIG_SPACE 10 // large space between controls #define SMALL_SPACE 4 // small space between controls #define MAX_SIZE_FRACTION 0.90 // percent of desktop which the window may ocupy // // Windows message IDs for all buttons // #define CB_GRAB 101 // id for grab push button #define CB_STOP 102 // id for stop push button #define CB_DONE 103 // id for grabbing done push button #define CB_CANCEL 104 // id for cancel all push button #define CB_TOGGLE 110 // id for capture toggling // NOTE: The toggle button is invisible. // it is there to add keyboard acceleration. //*************************************************************************** // FUNCTION PROTOTYPES AND MACROS //*************************************************************************** BOOL CaptureFrame(int iWidth, int iHeight, short* psPixels, int iBufferLength, double& dExposure); BOOL CALLBACK AcquisitionWndProc(HWND hWnd, UINT iMessage, UINT wParam, LONG lParam); BOOL CALLBACK DisplayWndProc(HWND hWnd, UINT iMessage, UINT wParam, LONG lParam); void DisplayIMAQError(Int32 error); int OnGrab (void); int OnStop (void); DWORD CaptureThread(LPDWORD lpdwParam); // error checking macro #define errChk(fCall) if (error = (fCall), error < 0) {goto Error;} else //*************************************************************************** // GLOBALS // Yes, globals are bad programming, but the National Instruments // example code upon which this is based used globals extensively. // Plus, it is a pain to pass values to/from a windows procedure. // Ideally, the way to do this is to encapsulate all of these values // into a class or structure, but sometimes that can be more trouble // than it is worth. //*************************************************************************** static HINSTANCE g_hInstance; static CHAR g_pcAcquisitionClassName[] = "IMAQ Acquisition"; static CHAR g_pcDisplayClassName[] = "IMAQ Display"; static CHAR g_pcInterfaceName[1024]; // IMAQ camera interface to use static HWND g_hwndMainWindow; // Main window // Control handles static HWND g_hwndStopButton; static HWND g_hwndGrabButton; static HWND g_hwndPauseButton; static HWND g_hwndDoneButton; static HWND g_hwndCancelButton; static HWND g_hwndExposureLengthEdit; static HWND g_hwndInterfaceNameEdit; static HWND g_hwndFrameRateStatic; static HWND g_hwndDisplay; static HANDLE g_hThread; // the main capture thread // Imaq globals static SESSION_ID g_idSession = 0; // IMAQ session ID static INTERFACE_ID g_idInterface = 0; // IMAQ interface ID static BUFLIST_ID g_idBuflist = 0; // IMAQ buffer list ID static short* g_psBuffer=NULL; // acquisiton buffer static short* g_psDestBuffer; // destination buffer static DWORD g_dwRoiLeft; // Capture ROI left-edge coordinate static DWORD g_dwRoiTop; // Capture ROI top-edge coordinate static DWORD g_dwRoiWidth; // Capture ROI width static DWORD g_dwRoiHeight; // Capture ROI height static int g_iDisplayLeft; // left position of display window static int g_iDisplayTop; // top position of display window static int g_iDisplayWidth; // width of display window static int g_iDisplayHeight; // height of display window static double g_dExposure; // exposure setting static BOOL g_bStopGrab = FALSE; // Tell thread to stop static BOOL g_bSuccess = FALSE; // Did the user want to keep the captured image? static BOOL g_bStopped = TRUE; // Was grabbing stopped? static BOOL g_bCaptured = FALSE; // Has an image been captured? //*************************************************************************** // FUNCTIONS //*************************************************************************** //=========================================================================== // Java_AcquireIMAQ_1_Acquire // // Native Interface to Java code. This function is called from within Java // to fill out an array of 16 bit values with an image acquired via the IMAQ // interface. // JNIEXPORT jboolean JNICALL Java_AcquireIMAQ_1_Acquire( JNIEnv *env, // Java environment jobject obj, // reserved jint jiWidth, // Width of image to acquire jint jiHeight, // Height of image to acquire jshortArray jsaPixels, // Array of 16bit pixels to fill jdoubleArray jdaParams) // Array of capture parameters to pass to/from java { if ((jiWidth > MAX_CAPTURE_WIDTH) || (jiHeight > MAX_CAPTURE_HEIGHT)) { // We cannot capture anything bigger return FALSE; } jsize len = env->GetArrayLength(jsaPixels); jshort* pPixels = env->GetShortArrayElements(jsaPixels, FALSE); double dExposure = 1.0; jsize nParams = env->GetArrayLength(jdaParams); jdouble* adParams = NULL; if (nParams > 0) { adParams = env->GetDoubleArrayElements(jdaParams, FALSE); // retrieve the exposure setting dExposure = adParams[0]; } // Open up a window to capture a single frame jboolean bRet = CaptureFrame(jiWidth, jiHeight, pPixels, len, dExposure); if (bRet && (nParams > 0) && (adParams != NULL)) { // pass the exposure setting back to Java adParams[0] = dExposure; } // Must release array memory before returning env->ReleaseShortArrayElements(jsaPixels, pPixels, 0); if (adParams != NULL) { env->ReleaseDoubleArrayElements(jdaParams, adParams, 0); } return bRet; } //=========================================================================== // RegisterWndClass // // Registers all windows classes for this interface // BOOL RegisterWndClass(HINSTANCE hInstance) { WNDCLASS wndclass; // register the main window wndclass.style = CS_HREDRAW | CS_VREDRAW; wndclass.lpfnWndProc = (WNDPROC) DisplayWndProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; wndclass.hInstance = g_hInstance; wndclass.hIcon = NULL; wndclass.hCursor = LoadCursor (NULL, IDC_ARROW); wndclass.hbrBackground = (HBRUSH)GetStockObject(GRAY_BRUSH); wndclass.lpszMenuName = NULL; wndclass.lpszClassName = g_pcDisplayClassName; if (!RegisterClass (&wndclass)) return FALSE; // register the display window wndclass.style = CS_HREDRAW | CS_VREDRAW; wndclass.lpfnWndProc = (WNDPROC) AcquisitionWndProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; wndclass.hInstance = g_hInstance; wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION); wndclass.hCursor = LoadCursor (NULL, IDC_ARROW); wndclass.hbrBackground = GetSysColorBrush(COLOR_3DFACE); wndclass.lpszMenuName = NULL; wndclass.lpszClassName = g_pcAcquisitionClassName; if (!RegisterClass (&wndclass)) return FALSE; return TRUE; } #ifdef TEST_ACQUISITION //=========================================================================== // WinMain // // Here for test purposes // int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { g_hInstance = hInstance; if (!RegisterWndClass(hInstance)) return -1; int iW = 640; int iH = 480; double dExposure = 1.0; short* psPixels = new short[iW*iH]; CaptureFrame(iW, iH, psPixels, iW*iH, dExposure); delete psPixels; return 0; } #else //=========================================================================== // DllMain // // Called when the DLL is loaded // BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD fdwReason, LPVOID lpReserved) { switch(fdwReason) { case DLL_PROCESS_ATTACH: // The DLL is being mapped into process's address space // Do any required initialization on a per application basis, // return FALSE if failed g_hInstance = hInstance; if (!RegisterWndClass(hInstance)) return FALSE; break; case DLL_THREAD_ATTACH: // A thread is created. Do any required initialization on a per // thread basis break; case DLL_THREAD_DETACH: // Thread exits with cleanup break; case DLL_PROCESS_DETACH: // The DLL unmapped from process's address space. Do necessary // cleanup break; } return TRUE; } #endif // TEST_ACQUISITION //=========================================================================== // CaptureFrame // // Creates a user-interface window to capture a images on the IMAQ board // BOOL CaptureFrame(int iWidth, int iHeight, short* psPixels, int iBufferLen, double& dExposure) { MSG msg; HWND hTemp; char pcBuffer[64]; HCURSOR hOldCursor; hOldCursor = SetCursor(LoadCursor(NULL,IDC_WAIT)); strcpy(g_pcInterfaceName, "img0"); g_psDestBuffer = psPixels; g_dExposure = dExposure; // calculate the position of the ROI g_dwRoiLeft = (MAX_CAPTURE_WIDTH - iWidth) / 2; g_dwRoiWidth = iWidth; g_dwRoiTop = (MAX_CAPTURE_HEIGHT - iHeight) / 2; g_dwRoiHeight = iHeight; // calculate the size of the display window g_iDisplayWidth = iWidth; g_iDisplayHeight = iHeight; // retrieve the size of the desktop window to see if we will fit inside HWND hwndDesktop = GetDesktopWindow(); RECT rtDesktop; GetWindowRect(hwndDesktop, &rtDesktop); int iDesktopWidth = rtDesktop.right - rtDesktop.left; int iDesktopHeight = rtDesktop.bottom - rtDesktop.top; BOOL bHasVScroll = FALSE; while ((g_iDisplayHeight) > (iDesktopHeight * MAX_SIZE_FRACTION)) { // the display window will be too tall, scale it down g_iDisplayHeight -= 100; bHasVScroll = TRUE; } BOOL bHasHScroll = FALSE; while ((g_iDisplayWidth + 2*BIG_SPACE + CONTROL_WIDTH) > (iDesktopWidth * MAX_SIZE_FRACTION)) { // the display window will be too big, scale it down g_iDisplayWidth -= 100; bHasHScroll = TRUE; } // creates the main window g_hwndMainWindow = CreateWindow( g_pcAcquisitionClassName, "IMAQ Acquire", WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU, CW_USEDEFAULT, CW_USEDEFAULT, 100, 100, NULL, NULL, g_hInstance, NULL); // Create the display window DWORD dwStyle = WS_CLIPSIBLINGS | WS_CHILD | WS_VISIBLE; if (bHasVScroll) dwStyle |= WS_VSCROLL; if (bHasHScroll) dwStyle |= WS_HSCROLL; if (!(g_hwndDisplay = CreateWindow(g_pcDisplayClassName,"Display", dwStyle, 0, 0, g_iDisplayWidth, g_iDisplayHeight, g_hwndMainWindow, (HMENU)-1, g_hInstance, NULL))) return (FALSE); // Setup the display window scroll bars if (bHasVScroll) { SetScrollRange(g_hwndDisplay, SB_VERT, 0, g_dwRoiHeight - g_iDisplayHeight, TRUE); } if (bHasHScroll) { SetScrollRange(g_hwndDisplay, SB_HORZ, 0, g_dwRoiWidth - g_iDisplayWidth, TRUE); } g_iDisplayLeft = 0; g_iDisplayTop = 0; // Start adding controls to the window. This is done manually instead of // through a resource file to make things simpler. int x = g_iDisplayWidth + BIG_SPACE; int y = BIG_SPACE; int w = CONTROL_WIDTH; int h = CONTROL_HEIGHT; h = CONTROL_HEIGHT; // creates the interface name label if (!(hTemp = CreateWindow("Static","&Interface:",ES_LEFT | WS_CHILD | WS_VISIBLE, x, y,CONTROL_WIDTH,CONTROL_HEIGHT,g_hwndMainWindow,(HMENU)-1,g_hInstance,NULL))) return(FALSE); y += h; // creates the interface name edit box if (!(g_hwndInterfaceNameEdit = CreateWindow("Edit", g_pcInterfaceName, WS_TABSTOP | ES_LEFT | WS_CHILD | WS_VISIBLE | WS_BORDER,x, y, CONTROL_WIDTH, CONTROL_HEIGHT,g_hwndMainWindow,(HMENU)-1,g_hInstance,NULL))) return(FALSE); y += h + BIG_SPACE; // creates the exposure length label if (!(hTemp = CreateWindow("Static","&Exposure:",ES_LEFT | WS_CHILD | WS_VISIBLE,x, y,w,h,g_hwndMainWindow,(HMENU)-1,g_hInstance,NULL))) return(FALSE); y += h; // creates the Exposure Length edit box sprintf(pcBuffer, "%.2f", g_dExposure); if (!(g_hwndExposureLengthEdit = CreateWindow("Edit",pcBuffer,WS_TABSTOP | ES_LEFT | WS_CHILD | WS_VISIBLE | WS_BORDER,x, y, w, h,g_hwndMainWindow,(HMENU)-1,g_hInstance,NULL))) return(FALSE); y += h + BIG_SPACE; h = BUTTON_HEIGHT; // creates the Grab button if (!(g_hwndGrabButton = CreateWindow("Button","&Grab",WS_TABSTOP | BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_BORDER,x, y, w,h,g_hwndMainWindow,(HMENU)CB_GRAB,g_hInstance,NULL))) return(FALSE); y += h + SMALL_SPACE; // creates the stop button if (!(g_hwndStopButton = CreateWindow("Button","&Stop",WS_TABSTOP | BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_BORDER,x, y, w,h,g_hwndMainWindow,(HMENU)CB_STOP,g_hInstance,NULL))) return(FALSE); y += h + SMALL_SPACE; h = CONTROL_HEIGHT; // Creates a help message if (!(hTemp = CreateWindow("Static","(spacebar)",ES_CENTER | WS_CHILD | WS_VISIBLE, x, y, w,h,g_hwndMainWindow,(HMENU)-1,g_hInstance,NULL))) return(FALSE); // Create an invisible toggle button to handle the accelerator key if (!(hTemp = CreateWindow("Button","Toggle",BS_PUSHBUTTON | WS_CHILD | WS_DISABLED,x, y, w,h,g_hwndMainWindow,(HMENU)CB_TOGGLE,g_hInstance,NULL))) return(FALSE); y += h + BIG_SPACE; h = BUTTON_HEIGHT; // creates the Done button if (!(g_hwndDoneButton = CreateWindow("Button","&Done",WS_TABSTOP | BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE,x, y,w, h, g_hwndMainWindow,(HMENU)CB_DONE,g_hInstance,NULL))) return(FALSE); y += h + SMALL_SPACE; // creates the Cancel button if (!(g_hwndCancelButton = CreateWindow("Button","&Cancel",WS_TABSTOP | BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE,x, y,w, h, g_hwndMainWindow,(HMENU)CB_CANCEL,g_hInstance,NULL))) return(FALSE); y += h + BIG_SPACE; h = CONTROL_HEIGHT; // Creates the Frames per second label if (!(hTemp = CreateWindow("Static","Frames/sec:",ES_CENTER | WS_CHILD | WS_VISIBLE, x, y, w,40,g_hwndMainWindow,(HMENU)-1,g_hInstance,NULL))) return(FALSE); y += h; // creates the frame rate edit box if (!(g_hwndFrameRateStatic = CreateWindow("Edit","0",ES_LEFT | WS_CHILD | WS_VISIBLE | WS_BORDER,x, y,w,h,g_hwndMainWindow,(HMENU)-1,g_hInstance,NULL))) return(FALSE); y += CONTROL_HEIGHT + BIG_SPACE; // Open an IMAQ interface and a session BOOL bSessionOK = TRUE; if (imgInterfaceOpen (g_pcInterfaceName, &g_idInterface) != IMG_ERR_GOOD) { bSessionOK = FALSE; } else if (imgSessionOpen (g_idInterface, &g_idSession) != IMG_ERR_GOOD) { bSessionOK = FALSE; } if (!bSessionOK) { if(g_idSession != 0) imgClose (g_idSession, TRUE); if(g_idInterface != 0) imgClose (g_idInterface, TRUE); strcpy(g_pcInterfaceName, ""); SetWindowText(g_hwndInterfaceNameEdit, g_pcInterfaceName); } // now calculate the total size of the window RECT rtClient; int iClientWidth = g_iDisplayWidth + CONTROL_WIDTH + 2*BIG_SPACE; int iClientHeight = y; if (iClientHeight < g_iDisplayHeight) iClientHeight = g_iDisplayHeight; rtClient.left = (iDesktopWidth - iClientWidth) / 2; rtClient.right = rtClient.left + iClientWidth; rtClient.top = (iDesktopHeight - iClientHeight) / 2; rtClient.bottom = rtClient.top + iClientHeight; // adjust the window size to include the titlebar and borders AdjustWindowRect(&rtClient, WS_OVERLAPPEDWINDOW, FALSE); // resize main window to fit SetWindowPos(g_hwndMainWindow, HWND_TOP, rtClient.left, rtClient.top, rtClient.right - rtClient.left + 1, rtClient.bottom - rtClient.top + 1, SWP_NOZORDER); g_bSuccess = FALSE; EnableWindow(g_hwndFrameRateStatic, FALSE); EnableWindow(g_hwndStopButton, FALSE); //EnableWindow(g_hwndDoneButton, FALSE); //EnableWindow(g_hwndCancelButton, FALSE); // Display the main window SetCursor(hOldCursor); ShowWindow(g_hwndMainWindow, SW_SHOW); UpdateWindow(g_hwndMainWindow); // Create an accelerator table to make life easier ACCEL pAccel[] = { {FVIRTKEY, VK_SPACE, CB_TOGGLE}, {FVIRTKEY, VK_RETURN, CB_DONE}, {FVIRTKEY, VK_ESCAPE, CB_CANCEL} }; int nAccel = sizeof(pAccel) / sizeof(ACCEL); HACCEL hAccel = CreateAcceleratorTable(pAccel, nAccel); #if (GRAB_ON_STARTUP) // Start grabbing immediately OnGrab(); #endif // Main message loop while (GetMessage (&msg, NULL, 0, 0)) { if (!TranslateAccelerator(g_hwndMainWindow, hAccel, &msg)) { if (!IsDialogMessage(g_hwndMainWindow, &msg)) { TranslateMessage (&msg); DispatchMessage (&msg); } } } DestroyAcceleratorTable(hAccel); if (g_bSuccess) { // Copy the IMAQ buffer to the pixel buffer CopyMemory(g_psDestBuffer, g_psBuffer, sizeof(short)*iBufferLen); // Return any new exposure setting dExposure = g_dExposure; } // Close the IMAQ interface and the session if(g_idSession != 0) imgClose (g_idSession, TRUE); if(g_idInterface != 0) imgClose (g_idInterface, TRUE); return g_bSuccess; } //=========================================================================== // AcquisitionWndProc // // Window procedure for the main window. // BOOL CALLBACK AcquisitionWndProc(HWND hWnd, UINT iMessage, UINT wParam, LONG lParam) { WORD wmId; switch (iMessage) { case WM_COMMAND: wmId = LOWORD(wParam); switch (wmId) { case CB_DONE: if (!g_bStopped) { OnStop(); } if (g_bCaptured) g_bSuccess = TRUE; PostQuitMessage(0); break; case CB_CANCEL: if (!g_bStopped) { OnStop(); } PostQuitMessage(0); break; case CB_GRAB: // Grab button has been hit OnGrab(); break; case CB_STOP: // Stop button has been hit OnStop(); break; case CB_TOGGLE: if (g_bStopped) { OnGrab(); } else { OnStop(); } break; } break; case WM_DESTROY: if (!g_bStopped) { OnStop(); } PostQuitMessage(0); break; default: return DefWindowProc(hWnd, iMessage, wParam, lParam); break; } return 0; } //=========================================================================== // DisplayWndProc // // Window procedure for the image display window. Mostly handles scrolling. // BOOL CALLBACK DisplayWndProc(HWND hWnd, UINT iMessage, UINT wParam, LONG lParam) { WORD wReq, wPos; const int iPageSize = 50; switch (iMessage) { case WM_HSCROLL: wReq = LOWORD(wParam); wPos = HIWORD(wParam); switch (wReq) { case SB_LINELEFT: g_iDisplayLeft -= 1; SetScrollPos(hWnd, SB_HORZ, g_iDisplayLeft, TRUE); return 0; case SB_PAGELEFT: g_iDisplayLeft -= iPageSize; SetScrollPos(hWnd, SB_HORZ, g_iDisplayLeft, TRUE); return 0; case SB_LINERIGHT: g_iDisplayLeft += 1; SetScrollPos(hWnd, SB_HORZ, g_iDisplayLeft, TRUE); return 0; case SB_PAGERIGHT: g_iDisplayLeft += iPageSize; SetScrollPos(hWnd, SB_HORZ, g_iDisplayLeft, TRUE); return 0; case SB_THUMBTRACK: g_iDisplayLeft = wPos; SetScrollPos(hWnd, SB_HORZ, g_iDisplayLeft, TRUE); return 0; } break; case WM_VSCROLL: wReq = LOWORD(wParam); wPos = HIWORD(wParam); switch (wReq) { case SB_LINEUP: g_iDisplayTop -= 1; SetScrollPos(hWnd, SB_VERT, g_iDisplayTop, TRUE); return 0; case SB_PAGEUP: g_iDisplayTop -= iPageSize; SetScrollPos(hWnd, SB_VERT, g_iDisplayTop, TRUE); return 0; case SB_LINEDOWN: g_iDisplayTop += 1; SetScrollPos(hWnd, SB_VERT, g_iDisplayTop, TRUE); return 0; case SB_PAGEDOWN: g_iDisplayTop += iPageSize; SetScrollPos(hWnd, SB_VERT, g_iDisplayTop, TRUE); return 0; case SB_THUMBTRACK: g_iDisplayTop = wPos; SetScrollPos(hWnd, SB_VERT, g_iDisplayTop, TRUE); return 0; } break; } return DefWindowProc(hWnd, iMessage, wParam, lParam); } //=========================================================================== // OnGrab // // Function executed when the grab button is clicked // int OnGrab (void) { int error; char intfName[64]; char pcBuffer[32]; DWORD dwThreadId; g_bStopped = FALSE; // Get the interface name GetWindowText(g_hwndInterfaceNameEdit, intfName, 64); // Get the exposure setting GetWindowText(g_hwndExposureLengthEdit, pcBuffer, 32); g_dExposure = atof(pcBuffer); if (strcmp(intfName, g_pcInterfaceName)) { // This interface name has changed. Close the IMAQ interface // and the session and open a new one. if(g_idSession != 0) imgClose (g_idSession, TRUE); if(g_idInterface != 0) imgClose (g_idInterface, TRUE); strcpy(g_pcInterfaceName, intfName); // Open an IMAQ interface and a session errChk(imgInterfaceOpen (g_pcInterfaceName, &g_idInterface)); errChk(imgSessionOpen (g_idInterface, &g_idSession)); } // Set the ROI to the size of the Canvas so that it will fit nicely errChk(imgSetAttribute (g_idSession, IMG_ATTR_ROI_WIDTH, g_dwRoiWidth)); errChk(imgSetAttribute (g_idSession, IMG_ATTR_ROI_HEIGHT, g_dwRoiHeight)); errChk(imgSetAttribute (g_idSession, IMG_ATTR_ROI_LEFT, g_dwRoiLeft)); errChk(imgSetAttribute (g_idSession, IMG_ATTR_ROI_TOP, g_dwRoiTop)); #if 1 // Setup camera exposure if (g_dExposure > 1.0) { // add frames to get image. Round up to find number of frames. int nFrames = int(g_dExposure + 0.5); errChk(imgSetCameraAttributeString(g_idSession, "Exposure Time Setting", "Frame Blanking")); errChk(imgSetCameraAttributeNumeric(g_idSession, "Frame Shutter Time", nFrames)); } else if (g_dExposure == 1.0) { // Normal, 1 frame exposure errChk(imgSetCameraAttributeString(g_idSession, "Exposure Time Setting", "Normal")); } else { // Partial frame exposure int nTime = int(g_dExposure * MAX_EXPOSURE); if (nTime < 1) nTime = 1; errChk(imgSetCameraAttributeString(g_idSession, "Exposure Time Setting", "Electronic Shutter")); errChk(imgSetCameraAttributeNumeric(g_idSession, "Electronic Shutter Time", nTime)); } #endif // Setup and launch the grap operation errChk(imgGrabSetup (g_idSession, TRUE)); g_bStopGrab = FALSE; // Start the acquisition thread g_hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) CaptureThread, (LPDWORD*)&g_bStopGrab, 0, &dwThreadId); if (g_hThread == NULL) return 0; EnableWindow(g_hwndStopButton, TRUE); EnableWindow(g_hwndGrabButton, FALSE); //EnableWindow(g_hwndDoneButton, FALSE); //EnableWindow(g_hwndCancelButton, FALSE); Error : if(error<0) DisplayIMAQError(error); return 0; } //=========================================================================== // CaptureThread // // Main Capture thread // DWORD CaptureThread(LPDWORD lpdwParam) { static int nbFrame = 0, error; static int t1, t2; char buffer[32]; // the thread stop when g_bStopGrab goes to TRUE while(*((BOOL*)lpdwParam) == FALSE) { t2 = GetTickCount(); // Let NI-IMAQ manage the memory g_psBuffer = NULL; // Get the frame after tne next Vertical Blank errChk(imgGrab (g_idSession, (void**)&g_psBuffer, TRUE)); // Display it using imgPlot // Note that if you are using a 1424 and a camera with a bitdepth greater // that 8 bits, you need to set the flag parameter of imgPlot to match // the bit depth of the camera. See the "snap imgPlot" sample. imgPlot ((GUIHNDL)g_hwndDisplay, g_psBuffer, 0, 0, g_dwRoiWidth, g_dwRoiHeight, -g_iDisplayLeft, -g_iDisplayTop, IMGPLOT_MONO_12); // Calculate the number of frame per seconds every 10 frames nbFrame++; if (nbFrame>10) { sprintf(buffer, "%.2f", 1000.0 * (double)nbFrame / (double)(t2-t1)); SetWindowText (g_hwndFrameRateStatic, buffer); t1 = t2; nbFrame=0; } Error: if(error<0) { OnStop(); DisplayIMAQError(error); } } return 0; } //=========================================================================== // OnStop // // Function executed when the stop button is clicked // int OnStop(void) { int error; DWORD dwResult; if (g_bStopped) { // we are already stopped. No need to continue return 0; } // Stop the thread g_bStopGrab = TRUE; // Wait for the thread to end and kill it otherwise dwResult = WaitForSingleObject(g_hThread, 2000); if (dwResult == WAIT_TIMEOUT) TerminateThread(g_hThread, 0); // Stop the acquisition errChk(imgSessionStopAcquisition (g_idSession)); g_bCaptured = TRUE; Error: if(error<0) { DisplayIMAQError(error); } EnableWindow(g_hwndStopButton, FALSE); EnableWindow(g_hwndGrabButton, TRUE); //EnableWindow(g_hwndDoneButton, TRUE); //EnableWindow(g_hwndCancelButton, TRUE); CloseHandle (g_hThread); g_bStopped = TRUE; return 0; } //=========================================================================== // DisplayIMAQError // // in case of error this function will display a dialog box // with the error message // void DisplayIMAQError(Int32 error) { static Int8 ErrorMessage[256]; memset(ErrorMessage, 0x00, sizeof(ErrorMessage)); // converts error code to a message imgShowError(error, ErrorMessage); MessageBox(g_hwndMainWindow, ErrorMessage, "Imaq Sample", MB_OK); }