Creating the OpenCV LiveView Project
These are the steps to create a program that decodes compressed data continuously captured from an INFINICAM GbE-2 (monochrome model) in real time and streams it to a window (live view) using OpenCV.
-
Write the source code
Open the main file (e.g.
GbE2_OpenCV_LiveView.cpp) and replace its contents with the following code.#include <stdio.h>#include <stdlib.h>#include <windows.h>#include <PUCLIB.h> // PUCLIB header#include <opencv2/opencv.hpp> // OpenCV header// Context structure passed to the callback functionstruct LiveViewContext {UINT32 width;UINT32 height;UINT32 lineBytes;unsigned short qVals[PUC_Q_COUNT];unsigned char* pDecodedBuffer;bool isUpdated;CRITICAL_SECTION cs;};// Callback function automatically invoked by the SDK internally when an image is receivedvoid WINAPI ImageCallback(PPUC_XFER_DATA_INFO pXferData, void* pUserParam) {LiveViewContext* pCtx = (LiveViewContext*)pUserParam;if (!pXferData || !pXferData->pData || !pCtx || pXferData->isDamaged) {return;}EnterCriticalSection(&pCtx->cs);// High-speed multi-threaded decoding (decoded as 8-bit monochrome data)PUCRESULT ret = PUC_DecodeDataMultiThread(pCtx->pDecodedBuffer,0, 0,pCtx->width, pCtx->height,pCtx->lineBytes,pXferData->pData,pCtx->qVals,4 // Number of threads to use);if (ret == PUC_SUCCEEDED) {pCtx->isUpdated = true;}LeaveCriticalSection(&pCtx->cs);}int main() {printf("Starting INFINICAM GbE-2 OpenCV LiveView (monochrome)...\n");// 1. Initialize the SDKPUCRESULT ret = PUC_Initialize();if (ret != PUC_SUCCEEDED) {printf("Error: Failed to initialize the SDK. ErrorCode: %d\n", ret);return EXIT_FAILURE;}// 2. Search for a GbE-2 device on the networkPUC_DETECT_FILTER filter = { 0 };filter.nDeviceTypeFlags = PUC_DETECT_TARGET_GBE2; // Specify GbE-2PUC_DETECT_INFO detectInfo = { 0 };ret = PUC_DetectDevice2(&filter, &detectInfo);if (ret != PUC_SUCCEEDED || detectInfo.nDeviceCount == 0) {printf("Error: No GbE-2 camera was found. ErrorCode: %d\n", ret);return EXIT_FAILURE;}// 3. Open the first detected devicePUC_HANDLE hDevice = NULL;ret = PUC_OpenDevice2(0, &hDevice);if (ret != PUC_SUCCEEDED) {printf("Error: Failed to open the device. ErrorCode: %d\n", ret);return EXIT_FAILURE;}// 4. Get the resolution and quantization tableUINT32 width = 0, height = 0;PUC_GetResolution(hDevice, &width, &height);unsigned short qVals[PUC_Q_COUNT] = { 0 };PUC_GetQuantization2(hDevice, qVals);printf("Capture resolution: %u x %u pixels (monochrome)\n", width, height);// 5. Set the ring buffer count for continuous transferPUC_SetRingBufferCount(hDevice, 32);// 6. Prepare the decode buffer and contextUINT32 lineBytes = (width + 3) & ~3; // Align to a 4-byte boundaryunsigned long decodedSize = (unsigned long)lineBytes * height;unsigned char* pDecodedBuffer = (unsigned char*)malloc(decodedSize);if (pDecodedBuffer == NULL) {printf("Error: Memory allocation failed.\n");PUC_CloseDevice(hDevice);return EXIT_FAILURE;}LiveViewContext ctx = { 0 };ctx.width = width;ctx.height = height;ctx.lineBytes = lineBytes;ctx.pDecodedBuffer = pDecodedBuffer;memcpy(ctx.qVals, qVals, sizeof(qVals));ctx.isUpdated = false;InitializeCriticalSection(&ctx.cs);// 7. Create an OpenCV Mat object that directly references the decode buffer (CV_8UC1: 8-bit monochrome, 1 channel)cv::Mat displayImage(height, width, CV_8UC1, pDecodedBuffer, lineBytes);const char* windowName = "INFINICAM GbE-2 LiveView (Press ESC or Q to exit)";cv::namedWindow(windowName, cv::WINDOW_AUTOSIZE);// 8. Start continuous transferret = PUC_BeginXferData(hDevice, ImageCallback, &ctx);if (ret != PUC_SUCCEEDED) {printf("Error: Failed to start continuous transfer. ErrorCode: %d\n", ret);DeleteCriticalSection(&ctx.cs);free(pDecodedBuffer);PUC_CloseDevice(hDevice);return EXIT_FAILURE;}printf("Displaying live view... Press 'ESC' or 'Q' on the window to exit.\n");// 9. Main loop: draw to the OpenCV window and watch for key inputwhile (true) {EnterCriticalSection(&ctx.cs);bool updated = ctx.isUpdated;if (updated) {ctx.isUpdated = false;}LeaveCriticalSection(&ctx.cs);if (updated) {// Display the latest decoded buffercv::imshow(windowName, displayImage);}// Wait 1ms and check for key inputint key = cv::waitKey(1);if (key == 27 || key == 'q' || key == 'Q') { // ESC (27) or 'q' to exitprintf("Exiting due to user action.\n");break;}}// 10. CleanupPUC_EndXferData(hDevice);cv::destroyAllWindows();DeleteCriticalSection(&ctx.cs);free(pDecodedBuffer);PUC_CloseDevice(hDevice);return EXIT_SUCCESS;} -
Build and run
- Press
Ctrl+Shift+Bto build. - With the GbE-2 connected to the network, run with
Ctrl+F5. - Confirm that the OpenCV display window opens and the monochrome video is displayed in real time. Pressing
ESCorqon the keyboard exits normally.
- Press
Key Points for OpenCV Integration
Section titled “Key Points for OpenCV Integration”Zero-copy cv::Mat wrapping
Section titled “Zero-copy cv::Mat wrapping”In the code, the following section passes the pointer to the decode buffer (pDecodedBuffer) allocated with malloc directly to the OpenCV cv::Mat constructor.
cv::Mat displayImage(height, width, CV_8UC1, pDecodedBuffer, lineBytes);By doing this, the moment data is decompressed by PUC_DecodeDataMultiThread, it can be drawn immediately as OpenCV image data without any intervening memory copy. Since no memory access overhead occurs, low-latency display is possible without any drop in frame rate.
