OpenCV LiveView プロジェクトの作成
INFINICAM GbE-2(モノクロモデル)から連続して取得した圧縮データをリアルタイムに復号し、OpenCV のウィンドウ上にストリーミング表示(ライブビュー)するプログラムの作成手順です。
-
ソースコードの記述
メインファイル(
GbE2_OpenCV_LiveView.cppなど)を開き、以下のコードに書き換えます。#include <stdio.h>#include <stdlib.h>#include <windows.h>#include <PUCLIB.h> // PUCLIB ヘッダー#include <opencv2/opencv.hpp> // OpenCV ヘッダー// コールバック関数へ引き渡すコンテキスト構造体struct LiveViewContext {UINT32 width;UINT32 height;UINT32 lineBytes;unsigned short qVals[PUC_Q_COUNT];unsigned char* pDecodedBuffer;bool isUpdated;CRITICAL_SECTION cs;};// 画像受信時に SDK 内部から自動呼び出しされるコールバック関数void WINAPI ImageCallback(PPUC_XFER_DATA_INFO pXferData, void* pUserParam) {LiveViewContext* pCtx = (LiveViewContext*)pUserParam;if (!pXferData || !pXferData->pData || !pCtx || pXferData->isDamaged) {return;}EnterCriticalSection(&pCtx->cs);// 高速マルチスレッド復号(8bit モノクロデータとしてデコード)PUCRESULT ret = PUC_DecodeDataMultiThread(pCtx->pDecodedBuffer,0, 0,pCtx->width, pCtx->height,pCtx->lineBytes,pXferData->pData,pCtx->qVals,4 // 使用スレッド数);if (ret == PUC_SUCCEEDED) {pCtx->isUpdated = true;}LeaveCriticalSection(&pCtx->cs);}int main() {printf("INFINICAM GbE-2 OpenCV LiveView (モノクロ) 開始...\n");// 1. SDKの初期化PUCRESULT ret = PUC_Initialize();if (ret != PUC_SUCCEEDED) {printf("エラー: SDKの初期化に失敗しました。ErrorCode: %d\n", ret);return EXIT_FAILURE;}// 2. ネットワーク上の GbE-2 デバイスを検索PUC_DETECT_FILTER filter = { 0 };filter.nDeviceTypeFlags = PUC_DETECT_TARGET_HAWK; // GbE-2 を指定PUC_DETECT_INFO detectInfo = { 0 };ret = PUC_DetectDevice2(&filter, &detectInfo);if (ret != PUC_SUCCEEDED || detectInfo.nDeviceCount == 0) {printf("エラー: GbE-2 カメラが見つかりませんでした。ErrorCode: %d\n", ret);return EXIT_FAILURE;}// 3. 検出した最初のデバイスをオープンPUC_HANDLE hDevice = NULL;ret = PUC_OpenDevice2(0, &hDevice);if (ret != PUC_SUCCEEDED) {printf("エラー: デバイスのオープンに失敗しました。ErrorCode: %d\n", ret);return EXIT_FAILURE;}// 4. 解像度および量子化テーブルの取得UINT32 width = 0, height = 0;PUC_GetResolution(hDevice, &width, &height);unsigned short qVals[PUC_Q_COUNT] = { 0 };PUC_GetQuantization2(hDevice, qVals);printf("撮影解像度: %u x %u ピクセル (モノクロ)\n", width, height);// 5. 連続転送用のリングバッファ数の設定PUC_SetRingBufferCount(hDevice, 32);// 6. デコードバッファおよびコンテキストの準備UINT32 lineBytes = (width + 3) & ~3; // 4バイト境界に整列unsigned long decodedSize = (unsigned long)lineBytes * height;unsigned char* pDecodedBuffer = (unsigned char*)malloc(decodedSize);if (pDecodedBuffer == NULL) {printf("エラー: メモリ割り当てに失敗しました。\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. 復号バッファを直接参照する OpenCV Mat オブジェクトを作成 (CV_8UC1: 8bit モノクロ 1チャンネル)cv::Mat displayImage(height, width, CV_8UC1, pDecodedBuffer, lineBytes);const char* windowName = "INFINICAM GbE-2 LiveView (ESCまたはQキーで終了)";cv::namedWindow(windowName, cv::WINDOW_AUTOSIZE);// 8. 連続転送の開始ret = PUC_BeginXferData(hDevice, ImageCallback, &ctx);if (ret != PUC_SUCCEEDED) {printf("エラー: 連続転送の開始に失敗しました。ErrorCode: %d\n", ret);DeleteCriticalSection(&ctx.cs);free(pDecodedBuffer);PUC_CloseDevice(hDevice);return EXIT_FAILURE;}printf("ライブビュー表示中... ウィンドウ上で 'ESC' または 'Q' キーを押すと終了します。\n");// 9. メインループ:OpenCV ウィンドウへの描画とキー入力監視while (true) {EnterCriticalSection(&ctx.cs);bool updated = ctx.isUpdated;if (updated) {ctx.isUpdated = false;}LeaveCriticalSection(&ctx.cs);if (updated) {// 復号された最新バッファを表示cv::imshow(windowName, displayImage);}// 1ms 待機してキー入力をチェックint key = cv::waitKey(1);if (key == 27 || key == 'q' || key == 'Q') { // ESC (27) または 'q' で終了printf("ユーザー操作により終了します。\n");break;}}// 10. 後処理PUC_EndXferData(hDevice);cv::destroyAllWindows();DeleteCriticalSection(&ctx.cs);free(pDecodedBuffer);PUC_CloseDevice(hDevice);return EXIT_SUCCESS;} -
ビルドと実行
Ctrl+Shift+Bを押してビルドを行います。- GbE-2 をネットワークに接続した状態で
Ctrl+F5で実行します。 - OpenCV の表示ウィンドウが立ち上がり、リアルタイムにモノクロ映像が表示されることを確認します。キーボードの
ESCまたはqを押すと正常終了します。
OpenCV 連携のポイント
Section titled “OpenCV 連携のポイント”ゼロコピーでの cv::Mat ラップ
Section titled “ゼロコピーでの cv::Mat ラップ”コード内の以下の部分では、malloc で確保した復号用バッファ (pDecodedBuffer) のポインタを直接 OpenCV の cv::Mat コンストラクタへ渡しています。
cv::Mat displayImage(height, width, CV_8UC1, pDecodedBuffer, lineBytes);このように指定することで、PUC_DecodeDataMultiThread でデータが解凍された瞬間、メモリの再コピーを挟むことなく OpenCV の画像データとして即座に描画できます。メモリアクセスオーバーヘッドが発生しないため、フレームレート落としを起こさずに低遅延な表示が可能です。
