ドロップフレーム(コマ落ち)の取得
ICImagingControlのImageAvailableイベントで処理できなかったフレームを確認する方法を示しています。
Software | IC Imaging Control 3.4, Visual Studio™ 2019 |
---|---|
サンプル(C#) | getting_dropped_frames_cs_3.4.zip |
サンプル(VB.NET) | getting_dropped_frames_vb_3.4.zip |
何か重い処理が実行された時、ImageAvailableイベントハンドラーで処理できていないフレームドロップ(コマ落ち)が発生しているかもしれません。ICImagingCongtrolのリングバッファを使用すると ImageAvailable イベントハンドラーで処理できなかったフレームにアクセスする事ができます。ここでは、システムに取得されたけれども、処理されなかったフレームを「ドロップフレーム」としています。
ドロップフレームを推定するために、グローバル変数 LastHandledFrameIndexが定義されます。これは最後に処理されたリングバッファのインデックスとして使用されます。
// 最後に処理されたフレームのリングバッファインデックスを保存する
private int LastHandledFrameIndex;
ドロップフレームを取得するために.OverlayUpdateEventEnableプロパティを false にセットする必要があります。ICImagingControlが全てのフレームをメモリに取得するように、.LiveCaptureContinuousプロパティは true にセットします。フレームはImageAvailable イベントの中でイメージバッファから表示されるので、プロパティ.LiveDisplayはfalseに設定します。.ImageRingBufferSizeはドロップフレームを保持するために十分な大きさが必要です。このサンプルでは.ImageRingBufferSizeプロパティは60にセットされているので、60フレームがメモリ中に保持できます。
private void Form1_Load(object sender, EventArgs e)
{
icImagingControl1.ShowDeviceSettingsDialog();
if (icImagingControl1.DeviceValid )
{
icImagingControl1.LiveDisplayDefault = false;
icImagingControl1.LiveDisplayHeight = icImagingControl1.Height;
icImagingControl1.LiveDisplayWidth = icImagingControl1.Width;
icImagingControl1.LiveCaptureContinuous = true;
icImagingControl1.LiveDisplay = false;
// ドロップフレームを受け取るため、OverlayUpdateEventEnableは falseに設定します
icImagingControl1.OverlayUpdateEventEnable = false;
// イメージバッファのセット(十分な大きさが必要です)
icImagingControl1.ImageRingBufferSize = 60;
icImagingControl1.LiveStart();
}
}
ドロップフレームは ImageAvailableイベントハンドラーで検知されます。そのアルゴリズムは2つのステップを持ちます。まず、ドロップフレームのカウントが計算され、変数DroppedFramesCountに保持されます。もしDroppedFramesCountが1よりも大きければ、ドロップフレームが発生したという事になります。次に、ループの中でこのドロップフレームを表示し、DroppedFramesCountから1を引きます。これが2よりも小さくなるまでループします。
private void icImagingControl1_ImageAvailable(object sender, TIS.Imaging.ICImagingControl.ImageAvailableEventArgs e)
{
TIS.Imaging.ImageBuffer buffer = icImagingControl1.ImageBuffers[e.bufferIndex];
// 最後に処理されたバッファインデックスと現在のバッファインデックスの差分を計算します。
// この値がドロップフレームの有無を示します。
int DroppedFramesCount = e.bufferIndex - LastHandledFrameIndex;
// DroppedFramesCount が0よりも小さい場合、リングバッファは次のフレームの処理に移行します
if ( DroppedFramesCount < 0 )
DroppedFramesCount = icImagingControl1.ImageRingBufferSize + DroppedFramesCount;
// フレームドロップがあった場合、以下のループにより処理されなかったフレームを表示します。
while (DroppedFramesCount > 1)
{
// ドロップフレームのインデックスを計算する
int DroppedFrameIndex = LastHandledFrameIndex - DroppedFramesCount - 1;
// RingBufferIndexのオーバーフローをハンドルする
if (DroppedFrameIndex < 0)
{
//DroppedFrameIndexが負の値であることに注意!
DroppedFrameIndex = icImagingControl1.ImageRingBufferSize + DroppedFrameIndex;
}
// ドロップフレームを取得する
TIS.Imaging.ImageBuffer LostFrame = icImagingControl1.ImageBuffers[DroppedFrameIndex];
// ドロップフレームを表示する
icImagingControl1.DisplayImageBuffer(LostFrame);
DroppedFramesCount--;
}
// 重い処理をシミュレートするため、ここにスリープを挿入しています。
System.Threading.Thread.Sleep(300);
icImagingControl1.DisplayImageBuffer(buffer);
// 現在のフレームのリングバッファインデックスをLastHandledFrameIndexに保持する
// これは次回 ImageAvailableがコールされた際に使用されます
LastHandledFrameIndex = e.bufferIndex;
}