主要内容

このページの翻訳は最新ではありません。ここをクリックして,英語の最新版を参照してください。

動きに基づく複数のオブジェクトの追跡

この例では,静止カメラからのビデオ中で移動するオブジェクトを自動検出し,動きに基づいた追跡を実行する方法を説明します。

動くオブジェクトの検出と動きに基づく追跡は,アクティビティ認識,交通監視および自動車安全性など,多くのコンピュータービジョンアプリケーションでの重要な要素です。動きに基づくオブジェクト追跡の問題は,2つの部分に分けることができます。

  1. 各フレームでの動くオブジェクトの検出

  2. 同じオブジェクトに時間の経過と共に対応する検出の関連付け

動くオブジェクトの検出では,混合ガウスモデルに基づいた背景差分アルゴリズムを使用します。その結果得られる前景マスクにモルフォロジー演算を適用してノイズを除去します。最後にブロブ解析によって,動くオブジェクトに対応する可能性が高い連結ピクセルのグループを検出します。

検出を同じオブジェクトに関連付ける処理は,動きだけに基づいて行われます。各トラックの動きはカルマンフィルターによって推定されます。このフィルターは,各フレームにおけるトラックの位置を予測し,各検出が各トラックに割り当てられる確率を判定するために使用されます。

トラックの維持は,この例の重要な側面となります。どのフレームを取っても,トラックに割り当てられる検出もあれば,割り当てのない検出やトラックも存在します。割り当てのあるトラックは,対応する検出を使用して更新されます。割り当てのないトラックは不可視としてマークされます。割り当てのない検出は新しいトラックを開始します。

各トラックは,割り当てのない状態が続いたフレームの数をカウントします。カウントが指定のしきい値を超えると,そのオブジェクトは視野の外に出たと仮定され,トラックが削除されます。

詳細については,複数オブジェクトの追跡を参照してください。

この例は,本体部分が上部にあり,ヘルパールーチンが入れ子関数の形式になっている関数です。

函数MotionBasedMultiObjectTrackingExample ()

%创建系统对象,用于读取视频,检测移动对象,%并显示结果。obj = setupSystemObjects ();跟踪= initializeTracks ();创建一个空轨道数组。nextId = 1;%下一个曲目的ID%检测移动物体,并在视频帧间跟踪它们。hasFrame(obj.reader) frame = readFrame(obj.reader);[质心,bboxes, mask] = detectObjects(frame);predictNewLocationsOfTracks ();[assignments, unassigndtracks, unassignddetections] =...detectionToTrackAssignment ();updateAssignedTracks ();updateUnassignedTracks ();deleteLostTracks ();createNewTracks ();displayTrackingResults ();结束

系统对象の作成

ビデオフレームの読み取り,前景オブジェクトの検出および結果の表示に使用される系统对象を作成します。

函数obj = setupSystemObjects ()%初始化视频I/O创建对象从文件中读取视频,绘制跟踪%对象在每一帧,并播放视频。创建一个视频阅读器。obj。读者= VideoReader (“atrium.mp4”);%创建两个视频播放器,一个显示视频,%和1显示前景掩码。obj。maskPlayer =愿景。放像机(“位置”, [740, 400, 700, 400]);obj。放像机=愿景。放像机(“位置”, [20, 400, 700, 400]);%创建用于前景检测和blob分析的系统对象%前景检测器用于分割移动物体%的背景。它输出一个二进制掩码,其中像素值1的%对应前景,0的值对应前景%到背景。obj.detector =愿景。ForegroundDetector (“NumGaussians”3,...“NumTrainingFrames”现年40岁的“MinimumBackgroundRatio”, 0.7);%连接的前景像素组可能与移动相对应%的对象。blob analysis System对象用于查找这样的组%(称为“blobs”或“connected components”),并计算它们%特征,如面积、质心和边界框。obj。blobAnalyser =愿景。BlobAnalysis (“BoundingBoxOutputPort”,真的,...“AreaOutputPort”,真的,“CentroidOutputPort”,真的,...“MinimumBlobArea”, 400);结束

トラックの初期化

関数initializeTracksはトラックの配列を作成します。ここで,各トラックはビデオ内の動くオブジェクトを表す構造体です。この構造体の目的は,追跡されるオブジェクトの状態を維持することです。状態は,トラックへの検出の割り当て,トラックの終了および表示に使用される情報で構成されます。

構造体には次のフィールドが含まれています。

  • id:トラックの整数ID

  • bbox:表示に使用される,オブジェクトの現在の境界ボックス

  • kalmanFilter:動きに基づく追跡に使用される,カルマンフィルターオブジェクト

  • 年龄:トラックが最初に検出されてからのフレーム数

  • totalVisibleCount:トラックが検出された(可視であった)フレームの合計数

  • consecutiveInvisibleCount:トラックが連続して検出されなかった(不可視であった)フレームの数

ノイズの多い検出では,トラックが短時間で終了する傾向にあります。そのため,この例ではある程度の数のフレームで追跡されたオブジェクトのみを表示します。これが起こるのは,totalVisibleCountが指定のしきい値を超えたときです。

あるトラックに検出が1つも関連付けられない状態が数フレーム続くと,そのオブジェクトは視野の外に出たものと仮定され,トラックが削除されます。これが起こるのは,consecutiveInvisibleCountが指定のしきい値を超えたときです。トラックの追跡時間が短く,大部分のフレームで不可視としてマークされた場合も,トラックはノイズとして削除されます。

函数跟踪= initializeTracks ()创建一个空轨道数组跟踪=结构(...“id”{},...“bbox”{},...“kalmanFilter”{},...“年龄”{},...“totalVisibleCount”{},...“consecutiveInvisibleCount”, {});结束

オブジェクトの検出

関数detectObjectsは,検出されたオブジェクトの重心と境界ボックスを返します。また,入力フレームと同じサイズのバイナリマスクも返します。値が1のピクセルは前景に対応し,値が0のピクセルは背景に対応します。

この関数は前景検出器を使用して動きのセグメンテーションを行います。その後,結果のバイナリマスクに対してモルフォロジー演算を実行し,ノイズの多いピクセルを削除して,残りのブロブにある穴を塗りつぶします。

函数[质心,bboxes, mask] = detectObjects(frame)%检测前景。掩码= obj.detector.step(框架);应用形态学操作去除噪音和填充洞。Mask = imopen(Mask, strel()“矩形”[3 3]));Mask = imclose(Mask, strel()“矩形”[15、15]));= imfill(面具,面具“黑洞”);%执行blob分析以找到连接的组件。[~, centroids, bboxes] = obj.blobAnalyser.step(mask);结束

既存のトラックの新しい位置の予測

カルマンフィルターを使用して,現在のフレームにおける各トラックの重心を予測し,それに応じて境界ボックスを更新します。

函数predictNewLocationsOfTracks ()I = 1:length(tracks) bbox = tracks(I).bbox;预测赛道的当前位置。predictedCentroid =预测(跟踪(i) .kalmanFilter);移动边界框,使其中心位于%预测位置。predictedCentroid = int32(predictedCentroid) - bbox(3:4) / 2;跟踪(i)。bbox= [predictedCentroid, bbox(3:4)];结束结束

トラックへの検出の割り当て

現在のフレームにおけるオブジェクト検出は,コストを最小化することで既存のトラックに割り当てられます。コストは,トラックに対応する検出の負の対数尤度として定義されます。

アルゴリズムには2つの手順があります。

手順 1:愿景。KalmanFilter系统对象™の距离メソッドを使用して,すべての検出を各トラックに割り当てるコストを計算します。このコストでは,予測されたトラックの重心と検出の重心間のユークリッド距離が考慮されます。また,カルマンフィルターにより維持される予測の信頼度も含められます。結果はM行N列の行列に保存されます。ここでMはトラックの数,Nは検出の数です。

手順 2: 関数assignDetectionsToTracksを使用して,コスト行列で表される割り当て問題を解きます。関数は、コスト行列と、検出をトラックに割り当てない場合のコストを受け取ります。

検出をトラックに割り当てない場合のコストの値は,愿景。KalmanFilter距离メソッドで返される値の範囲によって決まります。この値は実験的に調整しなければなりません。設定が小さすぎると,新しいトラックが作成される可能性が高まり,トラックの断片化につながる可能性があります。逆に設定が大きすぎると,一連のバラバラな動くオブジェクトに単一のトラックが対応付けられる可能性があります。

関数assignDetectionsToTracksはハンガリアン法アルゴリズムのMunkresバージョンを用いて,総コストが最小になる割り当てを計算します。そして,割り当てられたトラックと検出での対応するインデックスを2つの列に含む,M行2列の行列を返します。また,割り当てのなかったトラックと検出のインデックスも返します。

函数[assignments, unassigndtracks, unassignddetections] =...detectionToTrackAssignment() nTracks = length(tracks);nDetections = size(质心,1);计算分配每个检测到每个轨道的成本。cost = 0 (nTracks, nDetections);i = 1:nTracks成本(i,:) =距离(tracks(i)。kalmanFilter、质心);结束解决分配问题。costOfNonAssignment = 20;[assignments, unassigndtracks, unassignddetections] =...assignDetectionsToTracks(成本、costOfNonAssignment);结束

割り当てられたトラックの更新

関数updateAssignedTracksは,割り当てられた各トラックを,対応する検出によって更新します。愿景。KalmanFilter正确的メソッドを呼び出して,推定位置を訂正します。次に,新しい境界ボックスを保存して,トラックの持続期間と合計可視カウントを1増やします。最後に,関数により不可視カウントが0に設定されます。

函数updateAssignedTracks() numAssignedTracks = size(赋值,1);i = 1:numAssignedTracks trackIdx = assignments(i, 1);detectionIdx = assignments(i, 2);质心=质心(detectionIdx,:);bbox = bboxes(detectionIdx,:);修正对物体位置的估计%使用新的检测。正确的(跟踪(trackIdx)。kalmanFilter、质心);将预测的边界框替换为检测到的%边界框。跟踪(trackIdx)。bbox = bbox;%更新曲目的年龄。跟踪(trackIdx)。年龄= tracks(trackIdx).age + 1;%更新的可见性。跟踪(trackIdx)。totalVisibleCount=...跟踪(trackIdx)。totalVisibleCount+ 1; tracks(trackIdx).consecutiveInvisibleCount = 0;结束结束

割り当てのないトラックの更新

割り当てのない各トラックを不可視としてマークし,その持続期間を1増やします。

函数updateUnassignedTracks ()i = 1:length(unassigndtracks) ind = unassigndtracks (i);跟踪(印第安纳州)。年龄= tracks(ind).age + 1; tracks(ind).consecutiveInvisibleCount =...跟踪(印第安纳州)。consecutiveInvisibleCount + 1;结束结束

失われたトラックの削除

関数deleteLostTracksは,多くのフレームで連続して不可視だったトラックを削除します。また,最近作成されたトラックのうち,不可視だったフレームの総数が多いものも削除します。

函数deleteLostTracks ()如果isempty(跟踪)返回结束invisibleForTooLong = 20;ageThreshold = 8;%计算轨道的年龄占它可见的百分比。年龄=(跟踪(:).age);totalVisibleCounts =(跟踪(:).totalVisibleCount);visibility = totalVisibleCounts ./年龄;找到“丢失”轨道的索引。lostds =(年龄<年龄阈值&能见度< 0.6...(跟踪(:)。consecutiveInvisibleCount] > = invisibleForTooLong;删除丢失的轨迹。跟踪=跟踪(~ lostInds);结束

トラックの新規作成

割り当てのない検出から新しいトラックを作成します。割り当てのない検出は,すべて新しいトラックの開始であると仮定します。実際には,サイズ,位置,外観など,他の手がかりを使用してノイズの多い検出を排除できます。

函数createNewTracks() centroids = centroids(unassignddetections,:);bboxes = bboxes(unassignddetections,:);I = 1:size(质心,1)Bbox = bboxes(i,:);%创建一个卡尔曼过滤器对象。kalmanFilter = configureKalmanFilter (“ConstantVelocity”...质心,[200,50],[100,25],100);创建一个新的轨道。newTrack =结构(...“id”nextId,...“bbox”bbox,...“kalmanFilter”kalmanFilter,...“年龄”, 1...“totalVisibleCount”, 1...“consecutiveInvisibleCount”, 0);%将它添加到轨道数组中。track (end + 1) = newTrack;%增加下一个id。nextId = nextId + 1;结束结束

追跡結果の表示

関数displayTrackingResultsは,ビデオフレームおよび前景マスクの上に各トラックの境界ボックスとラベルIDを描画します。その後,フレームとマスクをそれぞれのビデオプレーヤーに表示します。

函数displayTrackingResults ()%转换帧和掩码的uint8 RGB。= im2uint8帧(帧);Mask = uint8(repmat(Mask, [1, 1, 3])) .* 255;minVisibleCount = 8;如果~ isempty(跟踪)%噪声检测往往会导致短暂的轨迹。%只显示可见时间超过的轨道%最小帧数。reliableTrackInds =...(跟踪(:)。totalVisibleCount] > minVisibleCount;reliableTracks =跟踪(reliableTrackInds);%显示对象。如果未检测到对象%在此帧中,显示其预测的边界框。如果~ isempty (reliableTracks)获得边界框。bbox = cat(1, reliableTracks.bbox);%得到id。id = int32 ([reliableTracks (:) .id]);%为对象创建标签%,我们显示的是预测值而不是实际值%的位置。标签= cellstr (int2str (ids));predictedTrackInds =...[reliableTracks(:)。consecutiveInvisibleCount) > 0;isPredicted =细胞(大小(标签));isPredicted (predictedTrackInds) = {“预测”};标签= strcat(标签,isPredicted);在框架上绘制对象。= insertObjectAnnotation帧(帧,“矩形”...bboxes、标签);在蒙版上绘制对象。= insertObjectAnnotation(面具,面具“矩形”...bboxes、标签);结束结束%显示掩码和帧。obj.maskPlayer.step(面具);obj.videoPlayer.step(框架);结束

まとめ

この例では,複数の動くオブジェクトを検出して追跡するために,動きに基づくシステムを作成しました。異なるビデオを使用して,オブジェクトの検出と追跡を行えるかどうか試してみてください。また,検出,割り当て,削除の各手順でパラメーターを変更してみます。

この例では,すべてのオブジェクトが定速で直線運動することを仮定して,動きのみに基づく追跡を行いました。オブジェクトの動きがこのモデルから大きく外れる場合は,追跡エラーが発生する可能性があります。ここでは12番のラベルが付いた人物が木に隠されたときに追跡エラーが起きています。

追跡エラーの可能性を減らすには,等加速度のようなより複雑な運動モデルを使用するか,各オブジェクトに複数のカルマンフィルターを使用します。また,サイズ,形状,色など,検出を時間の経過と共に関連付けるための他の手がかりを取り入れることもできます。

结束