科 / 研 / 图 / 像 / 处 / 理
目标追踪 (Object tracking) 是一类常见的图像处理问题,例如 细胞追踪以及动物行为的追踪 等等。
之前的文章介绍了怎样利用 ImageJ 进行手动的细胞追踪:
但这些插件都是根据某一类数据进行编写的,缺乏灵活性和通用性。
而在遇到实际的追踪问题时,根据具体情景不同,追踪算法实现的复杂度和难度也不同。
不同成像条件、不同运动状况的细胞,需要不同的追踪算法
细胞追踪可以分为以下几个步骤:
1.分割(Segmentation)
2.关联(Linking)
3.过滤(Filtering)
推荐教程:https://www.youtube.com/watch?v=IIt1LHIHYc4
这篇文章会介绍最基本的一类细胞追踪问题,演示怎样利用 MATLAB (R2019a),对 2D 细胞进行追踪:
数据处理前分析:这是一类比较简单的细胞运动图像,优点在于:
1.细胞和背景之间对比度高,易于分割;
2.细胞之间没有粘连。
难点在于细胞会出现和消失,所以在追踪时需要区分新细胞的出现,以及细胞的消失。
一、细胞追踪
实例代码,公众号后台回复 “细胞追踪” 可获取 MATLAB 代码。
1.细胞分割
clear;close all;
grayThd = 4;
sizeThd = 500;
ImStack = imstackread('trackingDemo.tif');
ImStackBW = imgaussfilt(ImStack,3) > grayThd; % binarization
% image filtering
for ii = 1:size(ImStackBW,3)
ImStackBW(:,:,ii) = imfill(ImStackBW(:,:,ii),'holes'); % fill holes
ImStackBW(:,:,ii) = bwareaopen(ImStackBW(:,:,ii),sizeThd); % remove small particles
ImStackBW(:,:,ii) = imclearborder(ImStackBW(:,:,ii)); % remove cells on border
end
% get center coordinates of cells
cellPos = cell(1,size(ImStackBW,3)); % initialize cell array
for ii = 1:size(ImStackBW,3)
tmpPos = regionprops(ImStackBW(:,:,ii),'Centroid'); % get centroid
cellPos{ii} = cat(1,tmpPos.Centroid); % concatenate all cells of single frame
end
save('cellPos-AllFrames.mat','cellPos');
细胞追踪的 第一步是分割出细胞,并找出细胞的中心坐标,分割效果:
关键代码分析:
ImStack = imstackread('trackingDemo.tif');
ImStackBW = imgaussfilt(ImStack,3) > grayThd; % binarization
这里用到了之前提到的自定义函数:
这里使用的数据比较容易分割,所以 利用高斯模糊 imgaussfilt 去噪之后,可以用一个固定阈值进行分割。
cellPos = cell(1,size(ImStackBW,3)); % initialize cell array
for ii = 1:size(ImStackBW,3)
tmpPos = regionprops(ImStackBW(:,:,ii),'Centroid'); % get centroid
cellPos{ii} = cat(1,tmpPos.Centroid); % concatenate all cells of single frame
end
预先给 CellPos 变量分配一个空 array,可以提高运算速度。
这里利用 cell array,因为不同 frame 可能找到的细胞坐标不同。
2.细胞关联
clear; close all;
load('cellPos-AllFrames.mat');
distThd = 30; % unit:pixel
minTraceLength = 5; % cell has to exist at least 5 frames
ii = 1;
traceNum = 1;
cellTrace = [];
while ii < length(cellPos) % traverse all frames
tmpTrace = [];
tmpFrame = cellPos{ii}; % cells of current frame
if isempty(tmpFrame) % if all cells in this frame were linked, go to next frame
disp(['frame-',num2str(ii),' finished.']);
ii = ii + 1;
continue;
end
% set the first center point as seed
tmpSeed = [tmpFrame(1,:),ii]; % save as [x y t]
tmpTrace(1,:) = tmpSeed; % set current seed as trace start
cellPos{ii}(1,:) = []; % once seed is linked, remove it
% search every frame after that seed
for jj = ii+1:length(cellPos)
nextFrame = cellPos{jj};
[1:2),nextFrame)); % search the closest cell ] = min(pdist2(tmpSeed(
if minDist < distThd % the next cell is close enough, the seed can be linked
tmpSeed = [nextFrame(cellIdx,:),jj]; % set this cell as new seed
tmpTrace = cat(1,tmpTrace,tmpSeed); % add this cell to the trace
cellPos{jj}(cellIdx,:) = []; % remove the linked seed
else % if the trace is finished, stop searching
break;
end
end
if size(tmpTrace,1) >= minTraceLength % trace filtering
cellTrace{traceNum} = tmpTrace;
traceNum = traceNum + 1;
end
end
save('cellTrace.mat','cellTrace');
这里细胞关联用到的是最简单的 欧氏距离,通过寻找下一帧离细胞最近的那个细胞,进行 Linking。
从一帧开始,每一个细胞作为一个种子(seed),往后面的帧进行搜寻。
如果搜寻不到符合条件的下一个细胞,则该细胞的轨迹(trace)结束。
示意图
if size(tmpTrace,1) >= minTraceLength % trace filtering
cellTrace{traceNum} = tmpTrace;
traceNum = traceNum + 1;
end
这里也包含了轨迹过滤(trace filtering),如果这个 trace 出现时间过短(少于 5 帧),那么这一条 trace 很可能并不正确。
Trace filtering 有很多特征可以进行考虑,例如细胞的速度、运动方向等等。
往期回顾