主要内容

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

这个例子展示了如何使用愿景。KalmanFilter对象和configureKalmanFilter函数来跟踪对象。

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

函数kalmanFilterForTracking

介绍

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

  • 预测对象的未来位置

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

  • 便于将多个对象关联到它们的轨迹的过程

目标跟踪的挑战

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

showDetections ();

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

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

showTrajectory ();

可以观察到两个问题:

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

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

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

利用卡尔曼滤波跟踪单个目标

利用之前看到的视频trackSingleObject函数向您展示如何:

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

  • 使用预测正确的方法以消除跟踪系统中存在的噪声

  • 使用预测方法本身来估计球的位置时,它被框遮挡

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

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

帧= [];%视频帧detectedLocation = [];%检测到的位置trackedLocation = [];%跟踪位置标签=''给球打标签公用事业= [];%用于处理视频的工具

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

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

卡尔曼滤波解决了两种截然不同的情况:

  • 当检测到球时,卡尔曼滤波首先预测其在当前视频帧中的状态,然后利用新检测到的目标位置对其状态进行校正。这将生成一个过滤过的位置。

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

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

param = getDefaultParameters ();%得到工作良好的卡尔曼配置%在本例中trackSingleObject(参数);%可视化结果

探索卡尔曼滤波配置选项

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

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

配置kalmanFilter (MotionModel, InitialLocation, InitialEstimateError, MotionNoise, MeasurementNoise)

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

param = getDefaultParameters ();获得工作良好的参数参数。motionModel =“ConstantVelocity”%从常量加速开关%, ConstantVelocity%切换运动模型后,降低噪音规格项%对应于加速度。参数。initialEstimateError = param.initialEstimateError (1:2);参数。motionNoise = param.motionNoise (1:2);trackSingleObject(参数);%可视化结果

请注意,球出现在一个与预测位置完全不同的位置。从球被释放的时候起,由于地毯的阻力,它就不断地减速。因此,恒加速度模型是较好的选择。如果您保持恒定速度模型,那么无论您为其他值选择什么,跟踪结果都将是次优的。

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

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

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

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

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

通常,物体不会以恒定加速度或恒定速度运动。您使用MotionNoise来指定偏离理想运动模型的量。当运动噪声增加时,卡尔曼滤波器更多地依赖传入的测量值,而不是它的内部状态。试着尝试MotionNoise参数以了解更多有关其效果的信息。

既然您已经熟悉了如何使用卡尔曼滤波器以及如何配置它,那么下一节将帮助您了解如何将它用于多目标跟踪。

注意:为了简化上述示例中的配置过程,我们使用了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();公用事业= createUtilities(参数);trackedLocation = [];idx = 0;hasFrame(utilities.videoReader) frame = readFrame(utilities.videoReader);detectedLocation = detectObject(框架);显示当前视频帧的检测结果。annotateTrackedObject ();%为了突出测量噪声的影响,显示检测%结果为第40帧在一个单独的数字。Idx = Idx + 1;如果idx == 40 combinedImage = max(repmat(utilities. exe))foregroundMask, (1, 1, 3)), im2single(帧));图中,imshow (combinedImage);结束结束%,而%关闭用于显示单个视频帧的窗口。uiscopes.close (“所有”);结束

检测当前视频帧中的球。

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

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

函数accumulateResults annotateTrackedObject () ();将前景掩码与当前视频帧相结合,以便%表示检测结果。combinedImage = max (repmat(公用事业。foregroundMask, (1, 1, 3)), im2single(帧));如果~ isempty (trackedLocation)形状=“圆”;地区= trackedLocation;区域(:3)= 5;combinedImage = insertObjectAnnotation(combinedImage, shape,...地区,{标签},“颜色”“红色”);结束步骤(实用程序。放像机、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;结束结束

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

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