TrackObjects bug


I believe I found a bug in the TrackObjects module.
In EvaluateObjectOverlap, as I understand it, you basically fit every cell in the previous frame to its best fitting (according to the metric chosen, we are using Overlap) cell in the current frame. This seems to work well. The problem occurs when two cells in the previous frame have merged into a single cell (due to bad segmentation) and have best fitting for the same big merged cell. What happens now is that the cell id of the cell with the larger id becomes the id of the merged cell, and not the cell with the larger score (overlap in our case). In fact since, usually, the cell with the larger id is usually a younger cell it also has a smaller overlap.
My solution to this problem is rather simple: I check which cell has the largest overlap from all cells from the previous frame, and remove all the other cells.

This is the code of the corrected function (changed code is marked):

%%% SUBFUNCTION - EvaluateObjectOverlap
function [CurrentLabels, CurrentHeaders] = EvaluateObjectOverlap(CurrentLabelMatrix, PreviousLabelMatrix, PreviousLabels, PreviousHeaders, ChosenMetric)

% Much of the following code is adapted from CPrelateobjects

% We want to choose a previous objects’s progeny based on the most overlapping
% current object. We first find all pixels that are in both a previous and a
% current object, as we wish to ignore pixels that are background in either
% labelmatrix
ForegroundMask = (CurrentLabelMatrix > 0) & (PreviousLabelMatrix > 0);
NumberOfCurrentObj = length(unique(CurrentLabelMatrix(CurrentLabelMatrix > 0)));
NumberOfPreviousObj = length(unique(PreviousLabelMatrix(PreviousLabelMatrix > 0)));

% Use the Matlab full(sparse()) trick to create a 2D histogram of
% object overlap counts
CurrentPreviousLabelHistogram = full(sparse(CurrentLabelMatrix(ForegroundMask), PreviousLabelMatrix(ForegroundMask), ChosenMetric(ForegroundMask), NumberOfCurrentObj, NumberOfPreviousObj));

% Make sure there are overlapping current and previous objects
if any(CurrentPreviousLabelHistogram(:)),
% For each current obj, we must choose a single previous obj parent. We will choose
% this by maximum overlap, which in this case is maximum value in
% the child’s column in the histogram. sort() will give us the
% necessary parent (row) index as its second return argument.
[OverlapCounts, CurrentObjIndexes] = sort(CurrentPreviousLabelHistogram,1);

% Get the parent list.
CurrentObjList = CurrentObjIndexes(end, :);

% Nandle the case of a zero overlap -> no current obj
CurrentObjList(OverlapCounts(end, :) == 0) = 0;
%%%% ADDED CODE BEGIN %%%%%%%%%%%%%%%%%
% If two children have the same parent - then choose the one with the
% largest intersection and set the other to zero.
[sortedVals, indsOfVals] = sort(CurrentObjList);
identicalVals = find(diff(sortedVals) == 0);
maxIntersection = OverlapCounts(end, :);
i = 1;
while(i <= length(identicalVals))
    curVal = sortedVals(identicalVals(i));
    inds = identicalVals(i);
    while (i < length(identicalVals) && sortedVals(identicalVals(i+1)) == curVal)
        i = i + 1;
        inds = [inds, identicalVals(i)];
    inds = [inds, inds(end)+1];
    sameParentChildrenIndices = indsOfVals(inds);
    [sortedMaxInterVals, sortedMaxInterInds] = sort(maxIntersection(sameParentChildrenIndices));
    CurrentObjList(sameParentChildrenIndices(sortedMaxInterInds(1:end-1))) = 0;
    i = i + 1;
%%%% ADDED CODE END %%%%%%%%%%%%%%%%%    
% Transpose to a column vector
CurrentObjList = CurrentObjList';   

% No overlapping objects
CurrentObjList = zeros(NumberOfPreviousObj, 1);

% Update the label and header vectors: The following accounts for objects
% that have disappeared or newly appeared

% Disspeared: Obj in CurrentObjList set to 0, so drop label from list
CurrentLabels = zeros(1,NumberOfCurrentObj);
CurrentLabels(CurrentObjList(CurrentObjList > 0)) = PreviousLabels(CurrentObjList > 0);

% Newly appeared: Missing index in CurrentObjList, so add new label to list
idx = setdiff(1:NumberOfCurrentObj,CurrentObjList);
CurrentLabels(idx) = max(PreviousLabels) + (1:length(idx));

CurrentHeaders(CurrentObjList(CurrentObjList > 0)) = PreviousHeaders(CurrentObjList > 0);
CurrentHeaders(idx) = {’’};

Please correct me if this isn’t a bug…
Anyway, I hope this helps.


Hi Barak,

Thanks for pointing this out; this is indeed a bug. We will add your contribution to our MATLAB code and make sure the same behavior isn’t replicated in our upcoming CP 2.0 release.

Again, thanks!