主要内容

使用卡尔曼滤波器进行目标跟踪

方法的使用愿景。KalmanFilter对象和configureKalmanFilter函数跟踪对象。

这个例子是一个函数,其主体位于顶部,辅助例程以嵌套函数的形式出现。

函数kalmanFilterForTracking

简介

卡尔曼滤波器有很多用途,包括在控制、导航、计算机视觉和时间序列计量经济学中的应用。这个例子说明了如何使用卡尔曼滤波器跟踪对象,并关注三个重要的特性:

  • 预测目标的未来位置

  • 减少不准确检测带来的噪音

  • 促进将多个对象与它们的轨迹关联的过程

目标跟踪的挑战

在展示卡尔曼滤波器的使用之前,让我们先检查一下在视频中跟踪对象的挑战。下面的视频显示了一个绿色的球在地板上从左向右移动。

showDetections ();

球上方的白色区域突出显示使用该方法检测到的像素愿景。ForegroundDetector,将移动的物体从背景中分离出来。背景减法只找到了球的一部分,因为球和地板之间的对比度很低。换句话说,检测过程并不理想,并引入了噪声。

为了便于可视化整个物体轨迹,我们将所有视频帧叠加到单个图像上。“+”标记表示使用斑点分析计算的质心。

showTrajectory ();

可以观察到两个问题:

  1. 区域的中心通常与球的中心不同。换句话说,在测量球的位置时存在误差。

  2. 当球被盒子遮挡时,球的位置不可用,即测量缺失。

这两个挑战都可以通过使用卡尔曼滤波器来解决。

使用卡尔曼滤波器跟踪单个对象

使用之前看到的视频trackSingleObject函数显示如何:

  • 创建愿景。KalmanFilter通过使用configureKalmanFilter

  • 使用预测而且正确的方法按顺序消除跟踪系统中存在的噪声

  • 使用预测方法来估计球被盒子遮挡时的位置

卡尔曼滤波器参数的选择是具有挑战性的。的configureKalmanFilter函数有助于简化这个问题。关于这一点的更多细节可以在示例中找到。

trackSingleObject函数包含嵌套的helper函数。下面的顶级变量用于在嵌套函数之间传输数据。

Frame = [];%一帧视频detectedLocation = [];%检测到的位置trackedLocation = [];%跟踪位置标签=%球的标签公用事业= [];%用于处理视频的实用程序

跟踪单个对象的过程如下所示。

函数trackSingleObject(参数)创建实用程序用于读取视频,检测移动物体,%并显示结果。utilities = createUtilities(param);isTrackInitialized = false;hasFrame(utilities.videoReader) frame = readFrame(utilities.videoReader);发现球。[detectedLocation, isObjectDetected] = detectObject(frame);如果~ isTrackInitialized如果isObjectDetected当球是时,通过创建卡尔曼滤波器初始化一个轨道%首次检测到。initialLocation = computeInitialLocation(param, detectedLocation);kalmanFilter = configureKalmanFilter(param.motionModel,...initialLocation param.initialEstimateError,...参数。motionNoise param.measurementNoise);isTrackInitialized = true;trackedLocation = correct(kalmanFilter, detectedLocation);标签=“初始”其他的trackedLocation = [];标签=结束其他的使用卡尔曼滤波器跟踪球。如果isObjectDetected检测到球。通过调用predict来降低测量噪声%正确。预测(kalmanFilter);trackedLocation = correct(kalmanFilter, detectedLocation);标签=“纠正”其他的球不见了。预测球的位置。trackedLocation = predict(kalmanFilter);标签=“预测”结束结束annotateTrackedObject ();结束%,而showTrajectory ();结束

卡尔曼滤波器可以解决两种不同的情况:

  • 当球被检测到时,卡尔曼滤波器首先预测它在当前视频帧的状态,然后使用新检测到的物体位置来校正它的状态。这将产生一个过滤的位置。

  • 当球不见时,卡尔曼滤波器仅依靠它之前的状态来预测球的当前位置。

你可以通过叠加所有视频帧来看到球的轨迹。

param = getDefaultParameters();得到工作良好的卡尔曼构型%为本例trackSingleObject(参数);可视化结果

探索卡尔曼滤波器配置选项

配置卡尔曼滤波器可能非常具有挑战性。除了对卡尔曼滤波器的基本理解外,通常还需要进行实验,以便提出一组合适的配置参数。的trackSingleObject函数提供的各种配置选项configureKalmanFilter函数。

configureKalmanFilter函数返回一个卡尔曼滤波器对象。您必须提供5个输入参数。

kalmanFilter = configureKalmanFilter(MotionModel, InitialLocation, InitialEstimateError, MotionNoise, measuentnoise)

MotionModel设置必须与物体运动的物理特性相对应。你可以将它设置为恒定速度或恒定加速度模型。下面的例子说明了做出次优选择的后果。

param = getDefaultParameters();得到工作良好的参数参数。motionModel =“ConstantVelocity”%从ConstantAcceleration切换%到恒定速度切换运动模型后,删除噪声规格条目%对应加速度。参数。initialEstimateError = param.initialEstimateError(1:2);参数。motionNoise = param.motionNoise(1:2);trackSingleObject(参数);可视化结果

请注意,球出现在一个与预测位置完全不同的地方。从球被释放的那一刻起,由于地毯的阻力,它一直在减速。因此,恒加速度模型是更好的选择。如果保持匀速模型,那么无论其他值选择什么,跟踪结果都不是最优的。

通常,你会设置InitialLocation输入到第一次检测到物体的位置。你还可以设置InitialEstimateError矢量到大的值,因为初始状态可能是非常嘈杂的,因为它是由一个单一的检测。下图展示了错误配置这些参数的影响。

param = getDefaultParameters();得到工作良好的参数参数。initialLocation = [0,0];%不是基于实际检测的位置参数。initialEstimateError = 100*ones(1,3);%使用相对较小的值trackSingleObject(参数);可视化结果

在错误配置参数的情况下,卡尔曼滤波器返回的位置与物体的实际轨迹对齐之前,它需要执行几个步骤。

的值MeasurementNoise应根据检测器的精度来选择。对于不太精确的探测器,请将测量噪声设置为较大的值。下面的例子说明了错误配置的分割阈值的噪声检测。增加测量噪声导致卡尔曼滤波器更多地依赖于其内部状态而不是传入测量,从而补偿检测噪声。

param = getDefaultParameters();参数。segmentationThreshold = 0.0005;%较小的值导致噪声检测参数。measurementNoise = 12500;增加%的价值来补偿%用于测量噪声的增加trackSingleObject(参数);可视化结果

通常情况下,物体不会以恒定加速度或恒定速度移动。你可以使用MotionNoise指定与理想运动模型的偏差量。当你增加运动噪声时,卡尔曼滤波器更依赖于传入的测量,而不是它的内部状态。试着用MotionNoise参数以了解有关其效果的详细信息。

现在您已经熟悉了如何使用Kalman滤波器以及如何配置它,下一节将帮助您了解如何将它用于多个对象跟踪。

注意:为了简化上面示例中的配置过程,我们使用了configureKalmanFilter函数。这个函数做了几个假设。有关详细信息,请参阅函数的文档。如果需要对配置过程进行更高级的控制,可以使用愿景。KalmanFilter直接对象。

使用卡尔曼滤波器跟踪多个对象

跟踪多个对象带来了几个额外的挑战:

  • 多次探测必须与正确的轨道相关联

  • 你必须处理场景中出现的新对象

  • 当多个对象合并为一个检测时,必须保持对象的身份

愿景。KalmanFilter对象一起使用assignDetectionsToTracks功能可以帮助解决问题

  • 将检测分配给跟踪

  • 确定检测是否对应于一个新对象,换句话说,就是创建轨道

  • 就像在一个被遮挡的单一物体的情况下,预测可以用来帮助分离彼此接近的物体

要了解使用卡尔曼滤波器跟踪多个对象的更多信息,请参阅示例标题基于运动的多目标跟踪

示例中的实用函数

使用实用函数来检测目标并显示结果。本节说明示例如何实现这些函数。

获取创建卡尔曼滤波器和分割球的默认参数。

函数param = getDefaultParameters参数motionModel =“ConstantAcceleration”;参数。initialLocation =“与第一次发现相同”;参数。initialEstimateError = 1E5 * ones(1,3);参数。motionNoise = [25,10,1];参数。measurementNoise = 25;参数。segmentationThreshold = 0.05;结束

检测并注释视频中的球。

函数showDetections() param = getDefaultParameters();utilities = createUtilities(param);trackedLocation = [];Idx = 0;hasFrame(utilities.videoReader) frame = readFrame(utilities.videoReader);detectedLocation = detectObject(frame);%显示当前视频帧的检测结果。annotateTrackedObject ();为了突出测量噪声的影响,显示检测%的结果为第40帧在一个单独的图。Idx = Idx + 1;如果idx == 40 combinedImage = max(repmat(实用程序。foregroundMask, [1,1,3]), im2single(帧));图中,imshow (combinedImage);结束结束%,而关闭用于显示单个视频帧的窗口。uiscopes.close (“所有”);结束

检测当前视频帧中的球。

函数[detection, isObjectDetected] = detectObject(frame) grayImage = rgb2gray(im2single(frame));实用工具。foregroundMask =步骤(实用程序。foregroundDetector grayImage);检测=步骤(实用程序。blobAnalyzer utilities.foregroundMask);如果isempty(detection) isObjectDetected = false;其他的为了简化跟踪过程,只使用第一个检测到的对象。检测=检测(1,:);isObjectDetected = true;结束结束

显示当前的检测和跟踪结果。

函数accumulateResults annotateTrackedObject () ();将前景蒙版与当前视频帧结合,以便%表示检测结果。combinedImage = max(repmat(实用程序。foregroundMask, [1,1,3]), im2single(帧));如果~isempty(trackedLocation)形状=“圆”;region = trackedLocation;区域(:,3)= 5;combinedImage = insertObjectAnnotation(组合图像,形状,...地区,{标签},“颜色”“红色”);结束步骤(实用程序。放像机、combinedImage);结束

通过将所有视频帧叠加在一起来显示球的轨迹。

函数showTrajectory关闭用于显示单个视频帧的窗口。uiscopes.close (“所有”);创建一个图形来显示所有视频帧的处理结果。图;imshow (utilities.accumulatedImage / 2 + 0.5);持有;情节(utilities.accumulatedDetections (: 1),...utilities.accumulatedDetections (:, 2),k +的);如果~ isempty (utilities.accumulatedTrackings)情节(utilities.accumulatedTrackings (: 1),...utilities.accumulatedTrackings (:, 2),“r-o”);传奇(“检测”“跟踪”);结束结束

累积视频帧,检测位置和跟踪位置,以显示球的轨迹。

函数accumulateResults()公用事业。accumulatedImage = max(实用程序。accumulatedImage,框架);utilities.accumulatedDetections...= [utilities.accumulatedDetections;detectedLocation];utilities.accumulatedTrackings...= [utilities.accumulatedTrackings;trackedLocation];结束

为了便于说明,请选择卡尔曼滤波器使用的初始位置。

函数loc = computeInitialLocation(param, detectedLocation)如果比较字符串(param.initialLocation“与第一次发现相同”) loc = detectedLocation;其他的loc = param.initialLocation;结束结束

创建用于读取视频、检测移动对象和显示结果的实用程序。

函数utilities = createUtilities(参数)创建用于读取视频、显示视频、提取视频的系统对象%前景,并分析连接的组件。实用工具。视频阅读器=视频阅读器(“singleball.mp4”);实用工具。videoPlayer =视觉。放像机(“位置”[100100500400]);实用工具。foregroundDetector =视觉。ForegroundDetector (...“NumTrainingFrames”10“InitialVariance”, param.segmentationThreshold);实用工具。blobAnalyzer =视觉。BlobAnalysis (“AreaOutputPort”假的,...“MinimumBlobArea”, 70,“CentroidOutputPort”,真正的);实用工具。累加图像= 0;utilities.accumulatedDetections= zeros(0, 2); utilities.accumulatedTrackings = zeros(0, 2);结束
结束