静止背景下的卡尔曼多目标跟踪

最近学习了一下多目标跟踪,看了看MathWorks的关于Motion-Based Multiple Object Tracking的Documention。

官网链接:http://cn.mathworks.com/help/vision/examples/motion-based-multiple-object-tracking.html?s_tid=gn_loc_drop

程序来自matlab的CV工具箱Computer Vision System Toolbox。这种方法用于静止背景下的多目标检测与跟踪。

程序可以分为两部分,1.每一帧检测运动objects;

2.实时的将检测得到的区域匹配到相同一个物体;

检测部分,用的是基于高斯混合模型的背景剪除法;

参考链接:http://blog.pluskid.org/?p=39

所谓单高斯模型,就是用多维高斯分布概率来进行模式分类

其中μ用训练样本均值代替,Σ用样本方差代替,X为d维的样本向量。通过高斯概率公式就可以得出类别C属于正(负)样本的概率。

混合高斯模型(GMM)就是数据从多个高斯分布中产生的。每个GMM由K个高斯分布线性叠加而成。

P(x)=Σp(k)*p(x|k)     相当于对各个高斯分布进行加权(权系数越大,那么这个数据属于这个高斯分布的可能性越大)

而在实际过程中,我们是在已知数据的前提下,对GMM进行参数估计,具体在这里即为图片训练一个合适的GMM模型。

那么在前景检测中,我们会取静止背景(约50帧图像)来进行GMM参数估计,进行背景建模。分类域值官网取得0.7,经验取值0.7-0.75可调。这一步将会分离前景和背景,输出为前景二值掩码。

然后进行形态学运算,并通过函数返回运动区域的centroids和bboxes,完成前景检测部分。

跟踪部分,用的是卡尔曼滤波。卡尔曼是一个线性估计算法,可以建立帧间bboxs的关系。

跟踪分为5种状态: 1,新目标出现    2,目标匹配    3,目标遮挡    4,目标分离   5,目标消失。

卡尔曼原理在这儿我就不贴了,网上很多。

状态方程: X(k+1)=A(K+1,K)X(K)+w(K)    其中 X(k)=[x(k),y(k),w(k),h(k),v(k)], x,y,w,h,分别表示bboxs的横纵坐标,长,宽。

观测方程: Z(k)=H(k)X(k)+v(k)             w(k), v(k),不相关的高斯白噪声。

定义好了观测方程与状态方程之后就可以用卡尔曼滤波器实现运动目标的跟踪,步骤如下:

1)计算运动目标的特征信息(运动质心,以及外接矩形)。

2)用得到的特征信息初始化卡尔曼滤波器(开始时可以初始为0)。

3)用卡尔曼滤波器对下一帧中对应的目标区域进行预测,当下一帧到来时,在预测区域内进行目标匹配。

4)如果匹配成功,则更新卡尔曼滤波器

在匹配的过程中,使用的是匈牙利匹配算法,匈牙利算法在这里有很好的介绍:http://blog.csdn.net/pi9nc/article/details/11848327

匈牙利匹配算法在此处是将新一帧图片中检测到的运动物体匹配到对应的轨迹。匹配过程是通过最小化卡尔曼预测得到的质心与检测到的质心之间的欧氏距离之和实现的

具体可以分为两步:

1,  计算损失矩阵,大小为[M N],其中,M是轨迹数目,N是检测到的运动物体数目。

2, 求解损失矩阵

主要思路就是这么多,下面贴上matlab的demo,大家可以跑一跑。

  1. function multiObjectTracking()
  2.  
  3. % create system objects used for reading video, detecting moving objects,
  4. % and displaying the results
  5. obj = setupSystemObjects(); %初始化函数
  6. tracks = initializeTracks(); % create an empty array of tracks %初始化轨迹对象
  7.  
  8. nextId = ; % ID of the next track
  9.  
  10. % detect moving objects, and track them across video frames
  11. while ~isDone(obj.reader)
  12. frame = readFrame(); %读取一帧
  13. [centroids, bboxes, mask] = detectObjects(frame); %前景检测
  14. predictNewLocationsOfTracks(); %根据位置进行卡尔曼预测
  15. [assignments, unassignedTracks, unassignedDetections] = ...
  16. detectionToTrackAssignment(); %匈牙利匹配算法进行匹配
  17.  
  18. updateAssignedTracks();%分配好的轨迹更新
  19. updateUnassignedTracks();%未分配的轨迹更新
  20. deleteLostTracks();%删除丢掉的轨迹
  21. createNewTracks();%创建新轨迹
  22.  
  23. displayTrackingResults();%结果展示
  24. end
  25.  
  26. %% Create System Objects
  27. % Create System objects used for reading the video frames, detecting
  28. % foreground objects, and displaying results.
  29.  
  30. function obj = setupSystemObjects()
  31. % Initialize Video I/O
  32. % Create objects for reading a video from a file, drawing the tracked
  33. % objects in each frame, and playing the video.
  34.  
  35. % create a video file reader
  36. obj.reader = vision.VideoFileReader('atrium.avi'); %读入视频
  37.  
  38. % create two video players, one to display the video,
  39. % and one to display the foreground mask
  40. obj.videoPlayer = vision.VideoPlayer('Position', [, , , ]); %创建两个窗口
  41. obj.maskPlayer = vision.VideoPlayer('Position', [, , , ]);
  42.  
  43. % Create system objects for foreground detection and blob analysis
  44.  
  45. % The foreground detector is used to segment moving objects from
  46. % the background. It outputs a binary mask, where the pixel value
  47. % of corresponds to the foreground and the value of corresponds
  48. % to the background.
  49.  
  50. obj.detector = vision.ForegroundDetector('NumGaussians', , ... %GMM进行前景检测,高斯核数目为3,前40帧为背景帧,域值为0.7
  51. 'NumTrainingFrames', , 'MinimumBackgroundRatio', 0.7);
  52.  
  53. % Connected groups of foreground pixels are likely to correspond to moving
  54. % objects. The blob analysis system object is used to find such groups
  55. % (called 'blobs' or 'connected components'), and compute their
  56. % characteristics, such as area, centroid, and the bounding box.
  57.  
  58. obj.blobAnalyser = vision.BlobAnalysis('BoundingBoxOutputPort', true, ... %输出质心和外接矩形
  59. 'AreaOutputPort', true, 'CentroidOutputPort', true, ...
  60. 'MinimumBlobArea', );
  61. end
  62.  
  63. %% Initialize Tracks
  64. % The |initializeTracks| function creates an array of tracks, where each
  65. % track is a structure representing a moving object in the video. The
  66. % purpose of the structure is to maintain the state of a tracked object.
  67. % The state consists of information used for detection to track assignment,
  68. % track termination, and display.
  69. %
  70. % The structure contains the following fields:
  71. %
  72. % * |id| : the integer ID of the track
  73. % * |bbox| : the current bounding box of the object; used
  74. % for display
  75. % * |kalmanFilter| : a Kalman filter object used for motion-based
  76. % tracking
  77. % * |age| : the number of frames since the track was first
  78. % detected
  79. % * |totalVisibleCount| : the total number of frames in which the track
  80. % was detected (visible)
  81. % * |consecutiveInvisibleCount| : the number of consecutive frames for
  82. % which the track was not detected (invisible).
  83. %
  84. % Noisy detections tend to result in short-lived tracks. For this reason,
  85. % the example only displays an object after it was tracked for some number
  86. % of frames. This happens when |totalVisibleCount| exceeds a specified
  87. % threshold.
  88. %
  89. % When no detections are associated with a track for several consecutive
  90. % frames, the example assumes that the object has left the field of view
  91. % and deletes the track. This happens when |consecutiveInvisibleCount|
  92. % exceeds a specified threshold. A track may also get deleted as noise if
  93. % it was tracked for a short time, and marked invisible for most of the of
  94. % the frames.
  95.  
  96. function tracks = initializeTracks()
  97. % create an empty array of tracks
  98. tracks = struct(...
  99. 'id', {}, ... %轨迹ID
  100. 'bbox', {}, ... %外接矩形
  101. 'kalmanFilter', {}, ...%轨迹的卡尔曼滤波器
  102. 'age', {}, ...%总数量
  103. 'totalVisibleCount', {}, ...%可视数量
  104. 'consecutiveInvisibleCount', {});%不可视数量
  105. end
  106.  
  107. %% Read a Video Frame
  108. % Read the next video frame from the video file.
  109. function frame = readFrame()
  110. frame = obj.reader.step();%激活读图函数
  111. end
  112.  
  113. %% Detect Objects
  114. % The |detectObjects| function returns the centroids and the bounding boxes
  115. % of the detected objects. It also returns the binary mask, which has the
  116. % same size as the input frame. Pixels with a value of correspond to the
  117. % foreground, and pixels with a value of correspond to the background.
  118. %
  119. % The function performs motion segmentation using the foreground detector.
  120. % It then performs morphological operations on the resulting binary mask to
  121. % remove noisy pixels and to fill the holes in the remaining blobs.
  122.  
  123. function [centroids, bboxes, mask] = detectObjects(frame)
  124.  
  125. % detect foreground
  126. mask = obj.detector.step(frame);
  127.  
  128. % apply morphological operations to remove noise and fill in holes
  129. mask = imopen(mask, strel('rectangle', [,]));%开运算
  130. mask = imclose(mask, strel('rectangle', [, ])); %闭运算
  131. mask = imfill(mask, 'holes');%填洞
  132.  
  133. % perform blob analysis to find connected components
  134. [~, centroids, bboxes] = obj.blobAnalyser.step(mask);
  135. end
  136.  
  137. %% Predict New Locations of Existing Tracks
  138. % Use the Kalman filter to predict the centroid of each track in the
  139. % current frame, and update its bounding box accordingly.
  140.  
  141. function predictNewLocationsOfTracks()
  142. for i = :length(tracks)
  143. bbox = tracks(i).bbox;
  144.  
  145. % predict the current location of the track
  146. predictedCentroid = predict(tracks(i).kalmanFilter);%根据以前的轨迹,预测当前位置
  147.  
  148. % shift the bounding box so that its center is at
  149. % the predicted location
  150. predictedCentroid = int32(predictedCentroid) - bbox(:) / ;
  151. tracks(i).bbox = [predictedCentroid, bbox(:)];%真正的当前位置
  152. end
  153. end
  154.  
  155. %% Assign Detections to Tracks
  156. % Assigning object detections in the current frame to existing tracks is
  157. % done by minimizing cost. The cost is defined as the negative
  158. % log-likelihood of a detection corresponding to a track.
  159. %
  160. % The algorithm involves two steps:
  161. %
  162. % Step : Compute the cost of assigning every detection to each track using
  163. % the |distance| method of the |vision.KalmanFilter| System object. The
  164. % cost takes into account the Euclidean distance between the predicted
  165. % centroid of the track and the centroid of the detection. It also includes
  166. % the confidence of the prediction, which is maintained by the Kalman
  167. % filter. The results are stored in an MxN matrix, where M is the number of
  168. % tracks, and N is the number of detections.
  169. %
  170. % Step : Solve the assignment problem represented by the cost matrix using
  171. % the |assignDetectionsToTracks| function. The function takes the cost
  172. % matrix and the cost of not assigning any detections to a track.
  173. %
  174. % The value for the cost of not assigning a detection to a track depends on
  175. % the range of values returned by the |distance| method of the
  176. % |vision.KalmanFilter|. This value must be tuned experimentally. Setting
  177. % it too low increases the likelihood of creating a new track, and may
  178. % result in track fragmentation. Setting it too high may result in a single
  179. % track corresponding to a series of separate moving objects.
  180. %
  181. % The |assignDetectionsToTracks| function uses the Munkres' version of the
  182. % Hungarian algorithm to compute an assignment which minimizes the total
  183. % cost. It returns an M x matrix containing the corresponding indices of
  184. % assigned tracks and detections in its two columns. It also returns the
  185. % indices of tracks and detections that remained unassigned.
  186.  
  187. function [assignments, unassignedTracks, unassignedDetections] = ...
  188. detectionToTrackAssignment()
  189.  
  190. nTracks = length(tracks);
  191. nDetections = size(centroids, );
  192.  
  193. % compute the cost of assigning each detection to each track
  194. cost = zeros(nTracks, nDetections);
  195. for i = :nTracks
  196. cost(i, :) = distance(tracks(i).kalmanFilter, centroids);%损失矩阵计算
  197. end
  198.  
  199. % solve the assignment problem
  200. costOfNonAssignment = ;
  201. [assignments, unassignedTracks, unassignedDetections] = ...
  202. assignDetectionsToTracks(cost, costOfNonAssignment);%匈牙利算法匹配
  203. end
  204.  
  205. %% Update Assigned Tracks
  206. % The |updateAssignedTracks| function updates each assigned track with the
  207. % corresponding detection. It calls the |correct| method of
  208. % |vision.KalmanFilter| to correct the location estimate. Next, it stores
  209. % the new bounding box, and increases the age of the track and the total
  210. % visible count by . Finally, the function sets the invisible count to .
  211.  
  212. function updateAssignedTracks()
  213. numAssignedTracks = size(assignments, );
  214. for i = :numAssignedTracks
  215. trackIdx = assignments(i, );
  216. detectionIdx = assignments(i, );
  217. centroid = centroids(detectionIdx, :);
  218. bbox = bboxes(detectionIdx, :);
  219.  
  220. % correct the estimate of the object's location
  221. % using the new detection
  222. correct(tracks(trackIdx).kalmanFilter, centroid);
  223.  
  224. % replace predicted bounding box with detected
  225. % bounding box
  226. tracks(trackIdx).bbox = bbox;
  227.  
  228. % update track's age
  229. tracks(trackIdx).age = tracks(trackIdx).age + ;
  230.  
  231. % update visibility
  232. tracks(trackIdx).totalVisibleCount = ...
  233. tracks(trackIdx).totalVisibleCount + ;
  234. tracks(trackIdx).consecutiveInvisibleCount = ;
  235. end
  236. end
  237.  
  238. %% Update Unassigned Tracks
  239. % Mark each unassigned track as invisible, and increase its age by .
  240.  
  241. function updateUnassignedTracks()
  242. for i = :length(unassignedTracks)
  243. ind = unassignedTracks(i);
  244. tracks(ind).age = tracks(ind).age + ;
  245. tracks(ind).consecutiveInvisibleCount = ...
  246. tracks(ind).consecutiveInvisibleCount + ;
  247. end
  248. end
  249.  
  250. %% Delete Lost Tracks
  251. % The |deleteLostTracks| function deletes tracks that have been invisible
  252. % for too many consecutive frames. It also deletes recently created tracks
  253. % that have been invisible for too many frames overall.
  254.  
  255. function deleteLostTracks()
  256. if isempty(tracks)
  257. return;
  258. end
  259.  
  260. invisibleForTooLong = ;
  261. ageThreshold = ;
  262.  
  263. % compute the fraction of the track's age for which it was visible
  264. ages = [tracks(:).age];
  265. totalVisibleCounts = [tracks(:).totalVisibleCount];
  266. visibility = totalVisibleCounts ./ ages;
  267.  
  268. % find the indices of 'lost' tracks
  269. lostInds = (ages < ageThreshold & visibility < 0.6) | ...
  270. [tracks(:).consecutiveInvisibleCount] >= invisibleForTooLong;
  271.  
  272. % delete lost tracks
  273. tracks = tracks(~lostInds);
  274. end
  275.  
  276. %% Create New Tracks
  277. % Create new tracks from unassigned detections. Assume that any unassigned
  278. % detection is a start of a new track. In practice, you can use other cues
  279. % to eliminate noisy detections, such as size, location, or appearance.
  280.  
  281. function createNewTracks()
  282. centroids = centroids(unassignedDetections, :);
  283. bboxes = bboxes(unassignedDetections, :);
  284.  
  285. for i = :size(centroids, )
  286.  
  287. centroid = centroids(i,:);
  288. bbox = bboxes(i, :);
  289.  
  290. % create a Kalman filter object
  291. kalmanFilter = configureKalmanFilter('ConstantVelocity', ...
  292. centroid, [, ], [, ], );
  293.  
  294. % create a new track
  295. newTrack = struct(...
  296. 'id', nextId, ...
  297. 'bbox', bbox, ...
  298. 'kalmanFilter', kalmanFilter, ...
  299. 'age', , ...
  300. 'totalVisibleCount', , ...
  301. 'consecutiveInvisibleCount', );
  302.  
  303. % add it to the array of tracks
  304. tracks(end + ) = newTrack;
  305.  
  306. % increment the next id
  307. nextId = nextId + ;
  308. end
  309. end
  310.  
  311. %% Display Tracking Results
  312. % The |displayTrackingResults| function draws a bounding box and label ID
  313. % for each track on the video frame and the foreground mask. It then
  314. % displays the frame and the mask in their respective video players.
  315.  
  316. function displayTrackingResults()
  317. % convert the frame and the mask to uint8 RGB
  318. frame = im2uint8(frame);
  319. mask = uint8(repmat(mask, [, , ])) .* ;
  320.  
  321. minVisibleCount = ;
  322. if ~isempty(tracks)
  323.  
  324. % noisy detections tend to result in short-lived tracks
  325. % only display tracks that have been visible for more than
  326. % a minimum number of frames.
  327. reliableTrackInds = ...
  328. [tracks(:).totalVisibleCount] > minVisibleCount;
  329. reliableTracks = tracks(reliableTrackInds);
  330.  
  331. % display the objects. If an object has not been detected
  332. % in this frame, display its predicted bounding box.
  333. if ~isempty(reliableTracks)
  334. % get bounding boxes
  335. bboxes = cat(, reliableTracks.bbox);
  336.  
  337. % get ids
  338. ids = int32([reliableTracks(:).id]);
  339.  
  340. % create labels for objects indicating the ones for
  341. % which we display the predicted rather than the actual
  342. % location
  343. labels = cellstr(int2str(ids'));
  344. predictedTrackInds = ...
  345. [reliableTracks(:).consecutiveInvisibleCount] > ;
  346. isPredicted = cell(size(labels));
  347. isPredicted(predictedTrackInds) = {' predicted'};
  348. labels = strcat(labels, isPredicted);
  349.  
  350. % draw on the frame
  351. frame = insertObjectAnnotation(frame, 'rectangle', ...
  352. bboxes, labels);
  353.  
  354. % draw on the mask
  355. mask = insertObjectAnnotation(mask, 'rectangle', ...
  356. bboxes, labels);
  357. end
  358. end
  359.  
  360. % display the mask and the frame
  361. obj.maskPlayer.step(mask);
  362. obj.videoPlayer.step(frame);
  363. end
  364.  
  365. %% Summary
  366. % This example created a motion-based system for detecting and
  367. % tracking multiple moving objects. Try using a different video to see if
  368. % you are able to detect and track objects. Try modifying the parameters
  369. % for the detection, assignment, and deletion steps.
  370. %
  371. % The tracking in this example was solely based on motion with the
  372. % assumption that all objects move in a straight line with constant speed.
  373. % When the motion of an object significantly deviates from this model, the
  374. % example may produce tracking errors. Notice the mistake in tracking the
  375. % person labeled #, when he is occluded by the tree.
  376. %
  377. % The likelihood of tracking errors can be reduced by using a more complex
  378. % motion model, such as constant acceleration, or by using multiple Kalman
  379. % filters for every object. Also, you can incorporate other cues for
  380. % associating detections over time, such as size, shape, and color.
  381.  
  382. displayEndOfDemoMessage(mfilename)
  383. end

matlab示例程序--Motion-Based Multiple Object Tracking--卡尔曼多目标跟踪程序--解读的更多相关文章

  1. Motion-Based Multiple Object Tracking

    kalman filter tracking... %% Motion-Based Multiple Object Tracking % This example shows how to perfo ...

  2. Multiple Object Tracking using K-Shortest Paths Optimization简要

    参考文献:Multiple Object Tracking using K-Shortest Paths Optimization 核心步骤: 两步:一.detection 二.link detect ...

  3. MATLAB 例子研究 Motion-Based Multiple Object Tracking

    这个例子是用来识别视频中多个物体运动的.我要研究的是:搞清楚识别的步骤和相应的算法,识别出物体运动的轨迹. 详细参见官方帮助文档,总结如下: 移动物体的识别算法:a background subtra ...

  4. 多目标跟踪(MOT)论文随笔-POI: Multiple Object Tracking with High Performance Detection and Appearance Feature

    网上已有很多关于MOT的文章,此系列仅为个人阅读随笔,便于初学者的共同成长.若希望详细了解,建议阅读原文. 本文是tracking by detection 方法进行多目标跟踪的文章,最大的特点是使用 ...

  5. 论文笔记-Deep Affinity Network for Multiple Object Tracking

    作者: ShijieSun, Naveed Akhtar, HuanShengSong, Ajmal Mian, Mubarak Shah 来源: arXiv:1810.11780v1 项目:http ...

  6. [Object Tracking] Overview of Object Tracking

    From: 目标跟踪方法的发展概述 From: 目标跟踪领域进展报告 通用目标的跟踪 经典目标跟踪方法 2010 年以前,目标跟踪领域大部分采用一些经典的跟踪方法,比如 Meanshift.Parti ...

  7. 论文笔记:Visual Object Tracking based on Adaptive Siamese and Motion Estimation Network

    Visual Object Tracking based on Adaptive Siamese and Motion Estimation 本文提出一种利用上一帧目标位置坐标,在本帧中找出目标可能出 ...

  8. Object Tracking Benchmark

    Abstract 问题: 1)evaluation is often not suffcient 2)biased for certain types of algorthms 3)datasets ...

  9. Online Object Tracking: A Benchmark 论文笔记(转)

    转自:http://blog.csdn.net/lanbing510/article/details/40411877 有博主翻译了这篇论文:http://blog.csdn.net/roamer_n ...

随机推荐

  1. ubuntu SecureCRT破解

    操作过程: 操作过程都在终端中执行.Ubuntu 的破解 : 下载程序:   wget 链接: https://pan.baidu.com/s/1nvdJl7j 密码: 2ryk 运行破解 /usr/ ...

  2. Rhel6-cacti+nagios+ganglia(apache)配置文档

    (lamp平台) 系统环境: rhel6 x86_64 iptables and selinux disabled 主机: 192.168.122.119 server19.example.com 1 ...

  3. [vijos P1391] 想越狱的小杉

    考前最后一题,竟然是第一次码SPFA,虽然这个算法早有耳闻,甚至在闻所未闻之前自己有过一个类似的想法,说白了就是广搜啊,但是敲起来还是第一次啊,而且这还不是真正意义上的SPFA. 完全按照自己想法来码 ...

  4. css布局之三列布局

    网站上使用三列布局的还是比较多的,不过三列和两列有些相似: 1.自适应三列 <!DOCTYPE html> <html lang="en"> <hea ...

  5. AngularJs的UI组件ui-Bootstrap分享(二)——Collapse

    Collapse折叠控件使用uib-collapse指令 <!DOCTYPE html> <html ng-app="ui.bootstrap.demo" xml ...

  6. jQueryMobile控件之复选框

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  7. xml 解析的四种方式

    =========================================xml文件<?xml version="1.0" encoding="GB2312 ...

  8. 【转载】知乎答案----孙志岗----Google 发布了程序员养成指南,国内互联网巨头是否也有类似的指南和课程推荐

    国内公司在复制国外商业模式的同时,也应复制人家的社会担当.所以,来答题了!就参考 Google 的框架,列一下中文的课程.大体上在线学完一个计算机专业,是基本不成问题的.但是,这不意味着你可以不上大学 ...

  9. lsof 解决无法删除文件夹问题

    今天在HPCC上面想要删除一个文件夹,结果说“Device or  resource busy". 于是google一下,发现这个是因为有程序正在运行,所以无法删除. 那么怎样解决? lso ...

  10. Java设计模式(十一) 享元模式

    原创文章,同步发自作者个人博客 http://www.jasongj.com/design_pattern/flyweight/.转载请注明出处 享元模式介绍 享元模式适用场景 面向对象技术可以很好的 ...