レーザーポインタの位置を特定する
概要
ライブビデオ中にあるレーザーポインタの位置を特定する方法を示しています。
サンプルプログラム
| 利用した開発環境 | Visual Studio™ 2019 | 
|---|---|
| SDK | IC Imaging Control 3.5(Python, C#, VB.NET) | 
| デバイスドライバ | Cam33U_setup,gigecam_setup,usbcam,AFU420_setup,usb2pro_drv | 
| デバイス | TISカメラ全般(MIPI CSI-2&FPD-Link IIIカメラを除く) | 
| サンプル(C#) | find_laser_point_cs_3.5.zip | 
| サンプル(VB.NET) | ー | 
| exeファイル アプリケーション  | 
    ー | 
| 別途ファイル | ー | 
| 関連参照URL | ー | 
サンプルツールの外観

このサンプルは取得イメージの中から1か所の赤いレーザーポインタを見つけ、十字マークと座標をオーバーレイ表示します。
private TIS.Imaging.OverlayBitmap overlayBitmap;
private TIS.Imaging.FrameSnapSink _fhs;private void Form1_Load_1(object sender, EventArgs e)
{
    icImagingControl1.ShowDeviceSettingsDialog();
    if (!icImagingControl1.DeviceValid)
    {
        cmdStartLive.Enabled = false;
        cmdSettings.Enabled = false;
    }
    // カメラの設定した解像度に合わせて表示画面を変更
    icImagingControl1.LiveDisplayDefault = false;
    icImagingControl1.LiveDisplaySize = icImagingControl1.Size;
    // イメージバッファのカラーフォーマットをICRGB24にセット
    _fhs = new TIS.Imaging.FrameSnapSink(TIS.Imaging.MediaSubtypes.RGB24);
    icImagingControl1.Sink = _fhs;
    // オーバーレイビットマップの配置をディスプレイパスにセット
    icImagingControl1.OverlayBitmapPosition = TIS.Imaging.PathPositions.Display;
    overlayBitmap = icImagingControl1.OverlayBitmapAtPath[TIS.Imaging.PathPositions.Display];
    // オーバーレイを有効に
    overlayBitmap.Enable = true;
    cmdFindLaser.Enabled = false;
    cmdStoplive.Enabled = false;
}
最初にプログラムは.ShowDeviceSettingsDialogを使って使用するデバイスを選択します。以降の動作については以下の手順となります。
オーバーレイビットマップに簡単にアクセスできるよう、グローバル変数 overlayBitmapを作成します。イメージバッファのカラーフォーマットを.MediaSubtypes.RGB24にセットします。プログラムは赤色のレーザーポインタを探して、十字マークのオーバーレイを赤色で表示します。
  OverlayBitmapを.OverlayBitmap.Enableとして有効にし、ディスプレイパスにセットします。これにより、描画した十字マークがレーザーポインタの探索アルゴリズムに影響しないようにします。
private void cmdFindLaser_Click(object sender, EventArgs e)
{
    int xLaser, yLaser;
    // Clear the overlay.
    overlayBitmap.Fill(overlayBitmap.DropOutColor);
    if (findLaserPoint(out xLaser, out yLaser))
    {
        DrawCrosshairs(xLaser, yLaser);
    }
    else
    {
        MessageBox.Show("No laser point found!");
    }
}[find!]ボタンがクリックされると、メソッドfindLaserPointがコールされます。レーザーポインタが見つかると、このメソッドはtrueを返し、変数xLaser, yLaserで座標データを取得する事ができます。十字マークをその座標に描画します。
private bool findLaserPoint(out int xLaser, out int yLaser)
{
    TIS.Imaging.IFrameQueueBuffer rval = _fhs.SnapSingle(TimeSpan.FromSeconds(1));
    BufferAccessHelper buf = new BufferAccessHelper(rval);
    int redPixel = 0;
    xLaser = 0;
    yLaser = 0;
    for (int y = 0; y < rval.FrameType.Height; y++)
    {
        for (int x = 0; x < rval.FrameType.Width; x++)
        {
            // x and y index for the imagebuffer.
            int indexXred = x * 3 + 2;
            int indexXgreen = x * 3 + 1;
            int indexXblue = x * 3 + 0;
            int indexY = rval.FrameType.Height - y - 1;
            if (buf[indexXred, indexY] > 220 & buf[indexXgreen, indexY] < 80 & buf[indexXblue, indexY] < 80)
            {
                // Count red pixels.
                redPixel++;
                Console.Write(buf[indexXred, indexY]+":" + buf[indexXgreen, indexY] + ":" + buf[indexXblue, indexY] );
                xLaser = xLaser + x;
                yLaser = yLaser + y;
            }
        }
    }メソッドfindLaserPointは cmdFindLaser_Clickからコールされ、イメージのレーザーポイントの探索の為に使用されます。この中で、SnapSingleをコールする事で、最新のイメージバッファを rvalにセットします。
このサンプルでは、赤の色情報だけを探索します。バッファ中のピクセルは座標 x , y で参照されます。ピクセルの赤データのみを使用するため、x 座標は3倍して使用されます。なぜなら、RGB24カラーフォーマットはピクセルあたりRGBの3bytesを持っているからです。その順序はB, G, R となっているので、赤だけを取り扱うためには、BとGデータの2Bytesをスキップする必要があるため、さらに2(Bytes)を追加します。
y座標も演算する必要があります。なぜならRGB24カラーフォーマットではバッファ上でイメージは上下逆さまに格納されているからです。抽出するための座標は計算され、それぞれ変数indexXred とindexYとして保持され、イメージバッファibのインデックスとして使用されます。
イメージ中のレーザーポインタは数ピクセルに及ぶある程度の大きさがあるはすです。その中心を割り出すため、輝度演算により抽出されたすべてのピクセルはredPixelにカウントされます。さらに、X, Y座標の値はxLaserとyLaserに加算されていきます。イメージ中のすべてのピクセルに対して処理が終わった後、xLaserとyLaserはそれぞれredPixelで割ることでレーザーポインタの中心を演算しています。(そのため、このサンプルで使用できるのは1点のレーザーポインタだけです。)
2つのfor ループはこのサンプルの画像処理アルゴリズムです。これらはイメージバッファ中の全てのX,Y座標のピクセルをチェックするためのものです。ここで、該当のピクセル輝度値が予め設定されたしきい値(230)よりも大きかった場合、そこにレーザーポインタがあると判断します。このメソッドの最後で抽出されたポイントから中心が計算されます。これらの値がレーザーポインタの位置として返されます。
private void DrawCrosshairs(int x, int y)
{
    overlayBitmap.DrawLine(Color.Red, x, y - 10, x, y + 10);
    overlayBitmap.DrawLine(Color.Red, x - 10, y, x + 10, y);
    overlayBitmap.DrawText(Color.White, x + 3, y + 2, x.ToString() + "," + y.ToString());
}
十字マークは2本の赤い線と座標を示した白のテキストで構成されます。overlayBitmap.DrawLineを2回コールすることで十字マークを作り、overlayBitmap.DrawTextをコールすることで座標のテキストを生成します。


