検出した時間を出力する方法

こちらの方法で個数等の出力を実行することができました。

それに加えて、カメラモードのライブビューで対象を検出し始めた時間と、その対象がどれだけの時間検出されたか(またはいつ検出されなくなったか)を出力することは可能でしょうか?
よろしくお願いします。

「いいね!」 3

ご質問ありがとうございます。

以下の例に対して開始時刻,現在時刻,追跡時間(ms)を追加で出力する例を紹介いたします。

スクリプト

using System.Text;
using System.IO;
// 検査をしない場合はnull 条件に一致する場合はtrue 条件に一致しない場合はfalse
bool? result = null;

// staticな変数を定義して画像間でカウントを共有
static int count = 0;
// blobのidと位置を覚えておくディクショナリ
static Dictionary<int, IBlob> idBlobDictionary = new Dictionary<int, IBlob>();
// 開始時刻とidを覚えておくディクショナリ
static Dictionary<int, DateTime> idStartTimeDictionary = new Dictionary<int, DateTime>();
// 距離閾値
const double distanceThreshold = 100.0;

// ペンの位置を取得
var blobs = GetInspectedBlobs("ペン検出");

// ペンが映っている時
if (blobs?.Any() == true)
{
    // 現在の時刻
    var dateTime = DateTime.Now;
    // ファイルが存在しているか
    var hasFile = File.Exists(@"D:\work\debug\test.csv");
    // csvに書き込み 既にファイルがある場合は続きから出力
    using (var sw = new StreamWriter(@"D:\work\debug\test.csv",hasFile, Encoding.UTF8))
    {
        // ファイルが存在しなかった時にヘッダーを出力
        if (!hasFile)
        {
            // ヘッダー
            sw.WriteLine("重心X,重心Y,前との距離,ID,累計カウント,開始時刻,現在時刻,追跡時間(ms)");
        }
        
        // トラッキング
        // 現在の画像でのペンの位置
        foreach (var blob in blobs)
        {
            var id = -1;
            var previousDistance = double.NaN;
            var blobPointD = CreatePointD(blob.Centroid.X, blob.Centroid.Y);
            // 前の画像のペンの位置
            foreach (var idBlob in idBlobDictionary)
            {
                var idBlobPointD = CreatePointD(idBlob.Value.Centroid.X, idBlob.Value.Centroid.Y);
                var distance = CalculateDistance(blobPointD, idBlobPointD);
                // 距離が近かったら同じものとみなす
                if (distance < distanceThreshold)
                {
                    // 前の画像と同じID
                    id = idBlob.Key;
                    // 情報を更新
                    idBlobDictionary[idBlob.Key] = blob;
                    previousDistance = distance;
                    break;
                }
            }

            // 前にいなかったペンだった時
            if (id == -1)
            {
                // 累計検出数を増やす
                count++;
                id = count;
                // ディクショナリに追加
                idBlobDictionary.Add(id, blob);
                // 現在の時刻を追加
                idStartTimeDictionary.Add(id, dateTime);
            }

            var startTime = idStartTimeDictionary[id];
            var startMs = startTime.Millisecond;
            var ms = dateTime.Millisecond;

            // ファイル書き込み
            sw.Write(blob.Centroid.X);
            sw.Write(",");
            sw.Write(blob.Centroid.Y);
            sw.Write(",");
            sw.Write(previousDistance);
            sw.Write(",");
            sw.Write(id);
            sw.Write(",");
            sw.Write(count);
            sw.Write(",");
            // エクセルで開くとmsが消失するのでシングルクォーテーションを挿入
            sw.Write("'" + startTime.ToString("yyyy/MM/dd HH:mm:ss") + "." + startMs);
            sw.Write(",");
            // エクセルで開くとmsが消失するのでシングルクォーテーションを挿入
            sw.Write("'" + dateTime.ToString("yyyy/MM/dd HH:mm:ss") + "." + ms);
            sw.Write(",");
            sw.Write((dateTime - startTime).TotalMilliseconds);
            sw.WriteLine("");
            
        }
    }
    // ペンが映っている時はtrue
    result = true;
}
// ペンが映っていない時
else
{
    // 映らなくなったら前の情報を破棄
    idBlobDictionary.Clear(); 
    // ペンが映っていない時はfalse
    result = false;
}

// カウント数を表示するために左上にBlobを描画
var blob = CreateBlob(CreatePointD(50, 50), 100, 100);
AddBlob("累計カウント : " + count, blob);

// resultは必ず最後の行に記述してください
result

初めて検出した時の時間を覚えておいて、現在時刻と差分を取って追跡時間を算出しています。

実行時の結果画面は前回のものと比べて変化はないので割愛いたします。

出力されるファイルは以下のようになります。

「いいね!」 3

ご回答ありがとうございます。
そちらのコードを実行したところ、同時刻に同じIDのものが別の位置に複数検出されているようなのですが、これはどういった意味になるのでしょうか?

よろしくお願い致します。

「いいね!」 2

ご質問ありがとうございます。

現在時刻が正しく取れていなさそうですね。
もしかしたら開始時刻も止まってしまっているかもしれません。

正直これだけでは原因が特定できなさそうなのですが、Windowsの時刻取得の部分の調子が悪い可能性もあります。

この現象は何度実行しても発生するのか教えていただけないでしょうか。

「いいね!」 1

はい、何度か試してみましたが毎回発生している現象のようです。

「いいね!」 2

ご回答ありがとうございます。

私の方で詳細を調査したいと思いますので、
もし差し支えなければ、以下のトピックを参考に弊社にワークスペースを送っていただけないでしょうか。

ありがとうございます。今、ワークスペースを送信させて頂きました。(ファイル名:57-3.5d-20231128-162147)

「いいね!」 1

ワークスペースのご提供ありがとうございます。
私の方で確認してわかったことを記述致します。

今回のスクリプトは検出した領域の重心が閾値以上離れている前提で書いています。

// 距離閾値
const double distanceThreshold = 100.0;

そのため、それより近いものが見つかってしまった場合、IDがおかしくなってしまいます。

なので、閾値を調整していただく必要があるのですが、
今回は領域検出の検査設定を少し見直せば改善できそうだったので、その設定を記載しておきます。
image

具体的には領域検出の学習精度があまり高くなく、分断されてしまっていたので、小間切れ状態で近くに複数検出されていました。
そのため、小さい部分を検出しないように設定したところ改善されたように見えました。

まずは、上記の方法で試して頂けないでしょうか。

ありがとうございます。
面積の設定を変更したところ、IDの重複はなくなったようです。
繰り返し学習すればこういった領域が細切れになるようなケースは減らすことができるのでしょうか?

「いいね!」 1

無事に動作したようで良かったです。

小間切れになるケースを防ぐには、うまくいかなかったデータを学習データに追加して学習することが有効です。
場合によっては、アノテーションのやり方を変えたりする必要もあります。
領域が小さい時は少し大きめに塗って他の領域と繋げると、AIも同じように繋げるように検知します。

少しずつデータを足していって、結果を見ながらアプローチしていくとより早く目標が達成できると思います。

承知しました。そちらの方法でまた学習を行ってみたいと思います。長い間ご回答いただきありがとうございました。

「いいね!」 1