コンテンツにスキップ

OpenCV LiveView プロジェクトの作成

INFINICAM GbE-2(モノクロモデル)から連続して取得した圧縮データをリアルタイムに復号し、OpenCV のウィンドウ上にストリーミング表示(ライブビュー)するプログラムの作成手順です。

  1. ソースコードの記述

    メインファイル(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;
    }
  2. ビルドと実行

    1. Ctrl + Shift + B を押してビルドを行います。
    2. GbE-2 をネットワークに接続した状態で Ctrl + F5 で実行します。
    3. OpenCV の表示ウィンドウが立ち上がり、リアルタイムにモノクロ映像が表示されることを確認します。キーボードの ESC または q を押すと正常終了します。

コード内の以下の部分では、malloc で確保した復号用バッファ (pDecodedBuffer) のポインタを直接 OpenCV の cv::Mat コンストラクタへ渡しています。

cv::Mat displayImage(height, width, CV_8UC1, pDecodedBuffer, lineBytes);

このように指定することで、PUC_DecodeDataMultiThread でデータが解凍された瞬間、メモリの再コピーを挟むことなく OpenCV の画像データとして即座に描画できます。メモリアクセスオーバーヘッドが発生しないため、フレームレート落としを起こさずに低遅延な表示が可能です。