Image 晶须的匹配轨迹

Image 晶须的匹配轨迹,image,matlab,cluster-analysis,Image,Matlab,Cluster Analysis,我正在做胡须追踪实验。我有老鼠拍打物体的高速视频(500fps)。在每一个这样的视频中,我都追踪老鼠鼻子和胡须的形状。由于跟踪是有噪声的,所以每一帧中的胡须数量可能不同(请参见所附图像中的两个连续帧,请注意左侧帧中出现的黄色假阳性胡须,但右侧帧中没有) 参见示例1: 作为跟踪的最终结果,对于每一帧,我得到不同数量的可变长度向量;每个向量对应一个晶须。在这一点上,我想匹配帧之间的胡须。我曾尝试使用Matlab的示例align来实现这一点,但它只能在某种程度上正常工作。其结果附在下面(附在显示227

我正在做胡须追踪实验。我有老鼠拍打物体的高速视频(500fps)。在每一个这样的视频中,我都追踪老鼠鼻子和胡须的形状。由于跟踪是有噪声的,所以每一帧中的胡须数量可能不同(请参见所附图像中的两个连续帧,请注意左侧帧中出现的黄色假阳性胡须,但右侧帧中没有)

参见示例1:

作为跟踪的最终结果,对于每一帧,我得到不同数量的可变长度向量;每个向量对应一个晶须。在这一点上,我想匹配帧之间的胡须。我曾尝试使用Matlab的示例align来实现这一点,但它只能在某种程度上正常工作。其结果附在下面(附在显示227帧以上所有胡须基点的图像中)

参见示例2:

我想运行一些算法来正确地对胡须进行聚类,这样每个胡须都被识别为自己,并在许多帧的过程中彼此分离。换句话说,我希望第二幅图像中的每个轻微正弦轨迹都被识别为一条轨迹。无论我使用什么排序算法,都应该考虑到胡须可能会在连续帧之间消失并重新出现。不幸的是,我已经没有主意了

有什么帮助吗


再次请记住,对于所附图像2中的每个点,我都有许多数据点,因为这只是一个晶须基点图,而实际上我有整个晶须长度的数据。

这就是我处理问题的方法。假设不同大小的数据向量位于称为
数据向量
单元
类型中,并且知道胡须的数量(
nSignals
),我会尝试将数据扩展到从原始数据导出的第二维度,然后在两个维度上执行k-means

因此,首先我将得到向量的最大大小,以便将数据转换为矩阵并进行
NaN
-填充

maxSize = -Inf;
for k = 1:nSignals
    if length(dataVectors{k}.data) > maxSize
        maxSize = length(dataVectors{k}.data);
    end
end
现在,我将数据提升到2的幂次方(或3,由您选择),使其成为2D。这只是一个非常简单的转换。但是你也可以在这里使用,然后将每个向量投影到其他向量上;然而,我不认为这是必要的,如果你的数据真的很大,它可能是低效的。目前,将数据提高到2的幂应该可以做到这一点。结果存储在第二个维度中

projDegree = 2;
projData = zeros(nSignals, maxSize, 2).*NaN;
for k = 1:nSignals
    vecSize = length(dataVectors{k}.data);
    projData(k, 1:vecSize, 1) = dataVectors{k}.data;
    projData(k, 1:vecSize, 2) = dataVectors{k}.data.*projDegree;
end
projData = reshape(projData, [], 2);
在这里,
projData
将在行
1
和列
1
中包含第一个胡须(或我在这里称之为信号)的原始数据,列
2
将具有新维度。假设您总共有
8个
胡须,那么,
projData
将有第1行
1
9
17
的数据,依此类推。第二行的数据为
2
10
18
,依此类推。如果您想返回原始数据,这一点很重要。此外,您还可以尝试使用不同的
projDegree
s,但我怀疑这会有很大的不同

现在我们在2D数据上执行;但是,我们提供初始点,而不是让它用k-means++确定它们。正如我在这里提出的,初始点是每个晶须的每个向量的第一个数据点。以这种方式,k-means将离开那里,并相应地移动到集群。我们将结果保存在
idxK

idxK = kmeans(projData,nSignals, 'Start', projData(1:nSignals, :));
就在这里。变量
idxK
将告诉您哪个数据点属于哪个集群

下面是我提出的解决方案的工作示例。第一部分只是尝试生成与您的数据相似的数据,您可以跳过它

rng(9, 'twister')
nSignals = 8;   % number of whiskers
n = 1000;       % number of data points
allData = zeros(nSignals, n);   % all the data will be stored here

% this loop will just generate some data that looks like yours
for k = 1:nSignals
    x = sort(rand(1,n));
    nPeriods = round(rand*9)+1;     % the sin can have between 1-10 periods
    nShiftAmount = round(randn*30);     % shift between ~ -100 to +100
    y = sin(x*2*pi*nPeriods) + (randn(1,n).*0.5);
    y = y + nShiftAmount;
    allData(k, :) = y;
end
nanIdx = round(rand(1, round(n*0.05)*nSignals).*((n*nSignals)-1))+1;   
allData(nanIdx) = NaN;      % about 5% of the data is now missing

figure(1);
for k = 1:nSignals
    nanIdx = ~isnan(allData(k, :));
    dataVectors{k}.data = allData(k, nanIdx);
    plot(dataVectors{k}.data, 'kx'), hold on;
end


让我知道这是否有帮助。

查看图2中的模式后,我建议您使用内核方法将数据转换到更高的维度,可能是2D或3D,并在更高的维度中执行
k-means
。在我看来,2次或3次多项式核应该可以做到这一点。如果你知道你要找多少胡须,那么在
k-means
中把它作为你的
k
。如果你提供一些样本数据,我可以为你写一个有效的解决方案。让我知道它是否有意义。
% determine the max size 
maxSize = -Inf;
for k = 1:nSignals
    if length(dataVectors{k}.data) > maxSize
        maxSize = length(dataVectors{k}.data);
    end
end

% making the data now into two dimensions and NaN pad
projDegree = 2;
projData = zeros(nSignals, maxSize, 2).*NaN;
for k = 1:nSignals
    vecSize = length(dataVectors{k}.data);
    projData(k, 1:vecSize, 1) = dataVectors{k}.data;
    projData(k, 1:vecSize, 2) = dataVectors{k}.data.*projDegree;
end
projData = reshape(projData, [], 2);
figure(2); plot(projData(:,1), projData(:,2), 'kx');
% run k-means using the first points of all measure as the initial points
idxK = kmeans(projData,nSignals, 'Start', projData(1:nSignals, :));
figure(3);
liColors = [{'yx'},{'mx'},{'cx'},{'bx'},{'kx'},{'gx'},{'rx'},{'gd'}];
for k = 1:nSignals
    plot(projData(idxK==k,1), projData(idxK==k,2), liColors{k}), hold on;
end
% plot results on original data
figure(4);
for k = 1:nSignals
    plot(projData(idxK==k,1), liColors{k}), hold on;
end