此示例显示如何使用卡曼过滤器
对象和configureKalmanFilter
用于跟踪对象的函数。
本例是一个函数,其主体位于顶部,辅助例程以嵌套函数的形式出现。
作用kalmanFilterForTracking
卡尔曼滤波器有许多用途,包括在控制、导航、计算机视觉和时间序列计量经济学中的应用。此示例说明了如何使用卡尔曼滤波器跟踪对象,并重点介绍了三个重要功能:
目标未来位置的预测
减少不准确检测带来的噪声
促进将多个对象与其轨迹关联的过程
在展示卡尔曼滤波器的使用之前,让我们先看看在视频中跟踪目标的挑战。下面的视频显示一个绿色的球在地板上从左向右移动。
showDetections ();
球上方的白色区域突出显示使用视觉前探地仪
,它将移动对象与背景分离。由于球与地板之间的对比度较低,背景减法只能找到球的一部分。换句话说,检测过程并不理想,并且会引入噪声。
为了方便地可视化整个物体轨迹,我们将所有视频帧叠加到单个图像上。“+”标记表示使用blob分析计算的质心。
show轨迹();
可以看到两个问题:
该区域的中心通常与球的中心不同。换句话说,在测量球的位置时存在误差。
当球被盒子挡住时,球的位置不可用,即测量丢失。
这两个挑战都可以通过使用卡尔曼滤波器来解决。
使用之前看到的视频trackSingleObject
函数显示如何:
创建卡曼过滤器
利用configureKalmanFilter
使用预测
和对的
一系列消除跟踪系统中噪声的方法
使用预测
方法本身来估计球的位置时,它被框遮挡
卡尔曼滤波器参数的选择具有挑战性。这个configureKalmanFilter
函数有助于简化此问题。关于这一点的更多细节可以在示例中进一步找到。
这个trackSingleObject
函数包括嵌套的辅助函数。以下顶级变量用于在嵌套函数之间传输数据。
帧=[];%视频帧检测位置=[];%检测到的位置trackedLocation = [];%跟踪位置标签='';给球打标签公用事业= [];%用于处理视频的工具
跟踪单个对象的过程如下所示。
作用trackSingleObject(参数)%创建用于读取视频、检测移动对象的实用程序,%并显示结果。utilities=createUtilities(参数);isTrackInitialized=false;虽然hasFrame(utilities.videoReader)frame=readFrame(utilities.videoReader);发现球。[detectedLocation,isObjectDetected]=DetectedObject(帧);如果~Istrack已初始化如果等深线探测%当球移动时,通过创建卡尔曼滤波器初始化轨迹%首次检测到。initialLocation = computeInitialLocation(param, detectedLocation);kalmanFilter = configureKalmanFilter (param.motionModel,...initialLocation,param.initialEstimateError,...参数。motionNoise param.measurementNoise);isTrackInitialized = true;trackkedlocation = correct(kalmanFilter, detectedLocation);标签=“初始”;其他的trackedLocation=[];标签='';结束其他的%使用卡尔曼滤波器跟踪球。如果等深线探测%球被发现了。%通过调用predict,然后调用%对。预测(卡尔曼滤波);trackedLocation=正确(kalmanFilter,detectedLocation);标签=“纠正”;其他的%球不见了。预测球的位置。trackedLocation=预测(kalmanFilter);标签=“预测”;结束结束annotateTrackedObject ();结束%,而show轨迹();结束
卡尔曼滤波器处理两种不同的情况:
当检测到球时,卡尔曼滤波首先预测其在当前视频帧中的状态,然后利用新检测到的目标位置对其状态进行校正。这将生成一个过滤过的位置。
当球丢失时,卡尔曼滤波器仅依靠其先前的状态来预测球的当前位置。
你可以通过叠加所有视频帧来看到球的轨迹。
param = getDefaultParameters ();%得到工作良好的卡尔曼配置%例如trackSingleObject(参数);%可视化结果
配置卡尔曼滤波器是非常具有挑战性的。除了对卡尔曼滤波器有基本的了解外,为了得到一组合适的配置参数,通常还需要进行实验。这个trackSingleObject
上面定义的函数可帮助您探索configureKalmanFilter
函数。
这个configureKalmanFilter
函数返回一个卡尔曼滤波对象。必须提供五个输入参数。
配置kalmanFilter (MotionModel, InitialLocation, InitialEstimateError, MotionNoise, MeasurementNoise)
这个运动模型设置必须与对象运动的物理特征相对应。可以将其设置为恒定速度或恒定加速度模型。以下示例说明了做出次优选择的后果。
param = getDefaultParameters ();获得工作良好的参数参数。motionModel =“康斯坦特维洛西蒂”;%从恒定加速转换%, ConstantVelocity%切换运动模型后,降低噪音规格项%对应于加速度。param.initialEstimateError=param.initialEstimateError(1:2);param.motionNoise=param.motionNoise(1:2);trackSingleObject(param);%可视化结果
请注意,球出现在与预测位置完全不同的位置。从球释放时起,由于地毯的阻力,它会不断减速。因此,恒定加速度模型是更好的选择。如果保持恒定速度模型,跟踪结果将是次优的al,无论您为其他值选择了什么。
通常,你会设置初始位置输入对象第一次被检测到的位置。你也可以设置初始估计误差由于初始状态可能是非常嘈杂的,因为它是从单个检测得到的。下图显示了错误配置这些参数的影响。
param = getDefaultParameters ();获得工作良好的参数param.initialLocation=[0,0];%不基于实际检测的位置参数initialEstimateError=100*个(1,3);%使用相对较小的值trackSingleObject(参数);%可视化结果
对于配置错误的参数,在卡尔曼滤波器返回的位置与目标的实际轨迹对齐之前,需要进行几步。
价值观测量噪声应根据探测器的精度进行选择。对于精度较低的探测器,将测量噪声设置为较大值。以下示例说明了错误配置的分割阈值的噪声检测。增加测量噪声会导致卡尔曼滤波器更多地依赖其内部状态,而不是传入的测量值,从而补偿检测噪声。
param = getDefaultParameters ();参数。segmentationThreshold = 0.0005;%较小的值会导致噪声检测参数测量噪声=12500;%增加值以补偿%表示测量噪声增加trackSingleObject(参数);%可视化结果
通常,对象不会以恒定加速度或恒定速度移动MotionNoise指定与理想运动模型的偏差量。当增加运动噪声时,卡尔曼滤波器更依赖于传入的测量值,而不是其内部状态。请尝试使用MotionNoise参数以了解更多有关其效果的信息。
现在您已经熟悉了如何使用卡尔曼滤波器以及如何配置它,下一节将帮助您了解如何将其用于多目标跟踪。
注:为了简化上述示例中的配置过程,我们使用configureKalmanFilter
函数。这个函数做了几个假设。有关详细信息,请参阅函数的文档。如果您需要对配置过程进行更大级别的控制,则可以使用卡曼过滤器
直接对象。
跟踪多个对象带来了几个额外的挑战:
多个检测必须与正确的轨迹相关联
必须处理场景中出现的新对象
当多个对象合并为一个检测时,必须维护对象标识
这个卡曼过滤器
对象与分配检测到跟踪
函数可以帮助解决
为轨道分配检测
确定检测是否对应于新对象,换句话说,轨迹创建
就像在单个物体被遮挡的情况下一样,预测可以用来帮助分离彼此接近的物体
要了解有关使用卡尔曼滤波器跟踪多个对象的更多信息,请参见标题为基于运动的多目标跟踪.
效用函数用于检测对象和显示结果。本节说明示例如何实现这些函数。
获取用于创建卡尔曼过滤器和分割球的默认参数。
作用param=getDefaultParameters param.motionModel=“持续加速”;参数初始位置=“与第一次检测相同”;param.initialEstimateError=1E5*个(1,3);param.motionNoise=[25,10,1];param.measurementNoise=25;param.segmentationThreshold=0.05;结束
检测和注释视频中的球。
作用showDetections() param = getDefaultParameters();公用事业= createUtilities(参数);trackedLocation = [];idx = 0;虽然hasFrame(utilities.videoReader)frame=readFrame(utilities.videoReader);detectedLocation=detectObject(frame);显示当前视频帧的检测结果。annotateTrackedObject ();%为了突出测量噪声的影响,显示检测%结果为第40帧在一个单独的数字。idx=idx+1;如果idx==40组合图像=max(repmat(utilities.foregroundMask[1,1,3]),im2single(frame));图,imshow(组合图像);结束结束%,而%关闭用于显示单个视频帧的窗口。uiscopes.close (“全部”);结束
检测当前视频帧中的球。
作用[detection, isObjectDetected] = detectObject(frame) grayImage = rgb2gray(im2single(frame)); / /检测图像实用工具。foregroundMask =步骤(实用程序。foregroundDetector grayImage);检测=步骤(实用程序。blobAnalyzer utilities.foregroundMask);如果isempty(检测)isObjectDetected=假;其他的%为了简化跟踪过程,只使用第一个检测到的对象。检测=检测(1,:);isObjectDetected = true;结束结束
显示当前检测和跟踪结果。
作用accumulateResults annotateTrackedObject () ();将前景掩码与当前视频帧相结合,以便%显示检测结果。CombineImage=最大值(repmat(utilities.foregroundMask[1,1,3]),im2single(frame));如果~ isempty (trackedLocation)形状=“圆”;地区= trackedLocation;区域(:3)= 5;combinedImage = insertObjectAnnotation(combinedImage, shape,...地区,{标签},“颜色”,“红色”);结束步骤(实用程序.视频播放器,组合图像);结束
通过将所有视频帧相互叠加显示球的轨迹。
作用展示轨迹%关闭用于显示单个视频帧的窗口。uiscopes.close (“全部”);%创建一个图形来显示所有视频帧的处理结果。图;imshow (utilities.accumulatedImage / 2 + 0.5);持有在;打印(实用程序。累计检测(:,1),...实用程序.累计检测(:,2),“k+”);如果~ isempty (utilities.accumulatedTrackings)情节(utilities.accumulatedTrackings (: 1),...公用设施.累计裂缝(:,2),“r-o”);传奇(“检测”,“追踪”);结束结束
累积视频帧、检测到的位置和跟踪的位置,以显示球的轨迹。
作用accumulateResults()公用事业。accumulatedImage = max(实用程序。accumulatedImage,框架);utilities.accumulatedDetections...=[实用程序.累计检测;检测位置];公用设施.累积裂缝...= [utilities.accumulatedTrackings;trackedLocation];结束
为了说明目的,选择卡尔曼滤波器使用的初始位置。
作用loc=计算初始分配(参数,检测位置)如果strcmp(参数初始位置,“与第一次检测相同”) loc = detectedLocation;其他的loc = param.initialLocation;结束结束
创建用于读取视频、检测移动对象和显示结果的实用程序。
作用公用事业= createUtilities(参数)%创建用于读取视频、显示视频和提取视频的系统对象%前台,并分析连接的组件。实用程序.videoReader=videoReader(“单球,mp4”);实用工具。放像机=愿景。放像机(“位置”[100100500400]);实用工具。foregroundDetector =愿景。ForegroundDetector (...“NumTrainingFrames”, 10,“InitialVariance”, param.segmentationThreshold);实用工具。blobAnalyzer =愿景。BlobAnalysis (“区域输出端口”假的,...“最小面积”, 70,“CentroidOutputPort”,真正的);实用工具。accumulatedImage = 0;utilities.accumulatedDetections= zeros(0, 2); utilities.accumulatedTrackings = zeros(0, 2);结束
结束