レーザーポインタの位置を特定する
ライブビデオ中にあるレーザーポインタの位置を特定する方法を示しています。
Software | IC Imaging Control 3.4, Visual Studio™ 2019 |
---|---|
サンプル(C#) | find_laser_point_cs_3.4.zip |
このサンプルは取得イメージの中から1か所の赤いレーザーポインタを見つけ、十字マークと座標をオーバーレイ表示します。
最初にプログラムは.ShowDeviceSettingsDialog を使って使用するデバイスを選択します。以降の動作については以下の手順となります。
オーバーレイビットマップに簡単にアクセスできるよう、グローバル変数 ob を作成します。
イメージバッファのカラーフォーマットを ICRGB24 (.MemoryCurrentGrabberColorformat = ICRGB24)にセットします。プログラムは赤色のレーザーポインタを探して、十字マークのオーバーレイを赤色で表示します。
OverlayBitmapを.OverlayBitmap.Enableとして有効にし、ディスプレイパスにセットします。これにより、描画した十字マークがレーザーポインタの探索アルゴリズムに影響しないようにします。
private TIS.Imaging.OverlayBitmap overlayBitmap;
private void Form1_Load_1(object sender, EventArgs e)
{
icImagingControl1.ShowDeviceSettingsDialog();
if (!icImagingControl1.DeviceValid)
{
cmdStartLive.Enabled = false;
cmdSettings.Enabled = false;
}
// イメージバッファのカラーフォーマットをICRGB24にセット
icImagingControl1.MemoryCurrentGrabberColorformat = TIS.Imaging.ICImagingControlColorformats.ICRGB24;
// オーバーレイビットマップの配置をディスプレイパスにセット
icImagingControl1.OverlayBitmapPosition = TIS.Imaging.PathPositions.Display;
overlayBitmap = icImagingControl1.OverlayBitmapAtPath[TIS.Imaging.PathPositions.Display];
// オーバーレイを有効に
overlayBitmap.Enable = true;
// 現在のフレームをImageActiveBufferに保存
icImagingControl1.LiveCaptureContinuous = true;
cmdFindLaser.Enabled = false;
cmdStoplive.Enabled = false;
}
find!ボタンがクリックされると、メソッドfindLaserPointがコールされます。レーザーポインタが見つかると、このメソッドはtrueを返し、変数xLaser,yLaserで座標データを取得する事ができます。十字マークをその座標に描画します。
private void cmdFindLaser_Click(object sender, EventArgs e)
{
int xLaser, yLaser;
// オーバーレイのクリア
overlayBitmap.Fill(overlayBitmap.DropOutColor);
if (findLaserPoint(out xLaser, out yLaser))
{
DrawCrosshairs(xLaser, yLaser);
}
else
{
MessageBox.Show("No laser point found!");
}
}
メソッドfindLaserPointはcmdFindLaser_Clickからコールされ、イメージのレーザーポイントの探索の為に使用されます。この中で、ImageBuffers.Activebufferをコールする事で、最新のイメージバッファを ibにセットします。
このサンプルでは、赤の色情報だけを探索します。バッファ中のピクセルは座標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 bool findLaserPoint(out int xLaser, out int yLaser)
{
TIS.Imaging.ImageBuffer imagebuffer = icImagingControl1.ImageActiveBuffer;
int redPixel = 0;
xLaser = 0;
yLaser = 0;
// 指定されたしきい値(230)よりも大きな値を持ったRedピクセルをチェックします
for (int y = 0; y < imagebuffer.Lines; y++)
{
for (int x = 0; x < imagebuffer.PixelPerLine; x++)
{
// イメージバッファ中のX.Yインデックス
int indexXred = x * 3 + 2;
int indexY = imagebuffer.Lines - y - 1;
if (imagebuffer[indexXred, indexY] > 230)
{
// Redピクセルをカウントします
redPixel++;
xLaser = xLaser + x;
yLaser = yLaser + y;
}
}
}
// 抽出されたすべてのRedピクセルから中心を計算します
if (redPixel > 0)
{
xLaser = xLaser / redPixel;
yLaser = yLaser / redPixel;
return true;
}
else
{
return false;
}
}
十字マークは2本の赤い線と座標を示した白のテキストで構成されます。ob.DrawLineを2回コールすることで十字マークを作り、ob.DrawTextをコールすることで座標のテキストを生成します。
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());
}