主要内容

使用卡尔曼滤波器进行对象跟踪

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

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

函数kalmanFilterForTracking

简介

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

  • 物体未来位置的预测

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

  • 促进多个对象与其轨迹的关联过程

目标跟踪的挑战

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

showDetections ();

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

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

showTrajectory ();

可以观察到两个问题:

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

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

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

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

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

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

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

  • 使用预测方法在球被盒子遮挡时,自行估计球的位置

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

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

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

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

函数trackSingleObject(参数)创建实用程序用于读取视频,检测移动物体,%并显示结果。utilities = createuutilities (param);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;trackedLocation =正确(kalmanFilter, detectedLocation);标签=“初始”其他的trackedLocation = [];标签=结束其他的使用卡尔曼滤波器跟踪球。如果isObjectDetected球被检测到。通过调用predict来减少测量噪声%正确。预测(kalmanFilter);trackedLocation =正确(kalmanFilter, detectedLocation);标签=“纠正”其他的球不见了。预测球的位置。trackkedlocation = predict(kalmanFilter);标签=“预测”结束结束annotateTrackedObject ();结束%,而showTrajectory ();结束

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

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

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

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

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

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

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

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

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

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参数,以了解更多有关其影响的资料。

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

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

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

跟踪多个对象会带来一些额外的挑战:

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

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

  • 当多个对象合并为一个检测时,必须维护对象标识

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

  • 将检测分配给轨道

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

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

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

示例中使用的实用函数

实用函数用于检测对象并显示结果。本节演示示例如何实现这些函数。

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

函数getDefaultParameters参数。motionModel =“ConstantAcceleration”;参数。initialLocation =“和第一次发现一样”;参数。initialEstimateError = 1E5 * ones(1,3);参数。motionNoise = [25, 10, 1];参数。measurementNoise = 25;参数。分割阈值= 0.05;结束

检测并注释视频中的球。

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

检测当前视频帧中的球。

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

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

函数accumulateResults annotateTrackedObject () ();%结合前景蒙版与当前视频帧,以便%表示检测结果。combinedImage = max(repmat(实用程序。foregroundMask, [1,1,3]), im2single(frame));如果~isempty(trackedLocation) shape =“圆”;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 = createuutilities (param)创建读取视频、显示视频、提取视频的系统对象%前景,并分析连接的组件。实用工具。videereader = videereader (“singleball.mp4”);实用工具。videoPlayer =视觉。放像机(“位置”[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);结束
结束