如何在MATLAB中跟踪多个对象的触摸?

时间:2015-09-11 14:41:50

标签: matlab image-processing computer-vision video-tracking

我有从图像中跟踪的多个对象的x,y像素坐标(3744x5616)。坐标存储在称为对象的结构中,例如

SearchanalyticsResource mySearchanalyticsResource = new SearchanalyticsResource(service);

SearchAnalyticsQueryRequest myRequest = new SearchAnalyticsQueryRequest(); 
myRequest.StartDate = "2015-08-01"; 
myRequest.EndDate = "2015-08-31"; 
myRequest.RowLimit = 10;

SearchanalyticsResource.QueryRequest myQueryRequest = mySearchanalyticsResource.Query(myRequest, site.SiteUrl); 
SearchAnalyticsQueryResponse myQueryResponse = myQueryRequest.Execute();

每个对象都由数字代码唯一标识,例如

objects(1).centre = [1868 1236]

我希望能够在每次任何两个物体彼此相差300像素的范围内进行记录。如果有任何对象正在触摸,那么最好的方法是检查,然后记录交互中涉及的两个对象的身份,就像对象33与对象34交互一样。

谢谢!

1 个答案:

答案 0 :(得分:3)

我现在能想到的最好的事情是蛮力方法。只需检查一个物体中心与其他物体的距离,然后手动检查距离是否为< 300像素。

如果你想要这么快,我们应该在没有任何工具箱的情况下做到这一点。您可以使用bsxfun使用vanilla MATLAB智能地执行此操作。首先,为每个对象的XY坐标创建单独的数组:

points = reshape([objects.centre], 2, []);
X = points(1,:);
Y = points(2,:);

[objects.centre]访问结构中每个centre字段的各个坐标,并将它们解压缩为逗号分隔列表。我重塑这个数组,使其为2行,其中第一行是X坐标,第二行是Y坐标。我提取出行并将它们放入单独的数组中。

接下来,为每个XY创建两个差异矩阵,其中行表示一个唯一坐标,列表示另一个唯一坐标。此矩阵内的值是ii点和jj点之间的差异:

Xdiff = bsxfun(@minus, X.', X);
Ydiff = bsxfun(@minus, Y.', Y);

bsxfun代表 B inary S ingleton E X pansion FUN ction。如果您熟悉repmat函数,它基本上会在引擎盖下复制矩阵和向量,以便您操作的两个输入具有相同的大小。在这种情况下,我正在做的是将XY指定为两个输入。一个是另一个的转置版本。通过此bsxfun自动广播每个输入,以便输入在维度上匹配。具体来说,第一个输入是X的列向量,因此这将重复并水平堆叠多次,与X中的值一样多。

类似地,这是针对Y值完成的。执行此操作后,对两个输出执行逐元素减法,然后在XY的一个点与另一个点之间得到组件式减法,其中该行为您提供第一个点,并且该列为您提供第二点。作为一个玩具示例,假设我们有X = [1 2 3]。使用上面的代码进行bsxfun调用会给出:

>> Xdiff = bsxfun(@minus, [1 2 3].', [1 2 3])

Xdiff =

##  |  1     2     3  
----------------------
 1  |  0    -1    -2
 2  |  1     0    -1
 3  |  2     1     0

我在输出中放置了一些其他字符,但这些字符仅用于说明,并为您提供参考点。通过从##列获取行值并从##行中的列值中减去,可以获得所需的减法。例如,第一行第二列说明1 - 2 = -1。第二行,第三列说明2 - 3 = -1。如果对XY点执行此操作,则会获得一个点与对称矩阵中所有其他点的分量距离。

你会注意到这是一个反对称矩阵,其中对角线都是0 ...有意义,因为一个点的一个维度相对于自身的距离应为0.左下角的三角形部分由于减法的顺序,矩阵的符号与右边的符号相反。如果用点2减去点1,则执行相反的减法会给出相反的符号。但是,我们假设行表示第一个对象,列表示第二个对象,因此您希望专注于较低一半。

现在,计算距离,并确保将上半部或下三角半设置为NaN,因为在计算距离时,符号会被忽略。如果你不忽略这一点,我们会发现互动的重复对象,因此对象3和对象1将是一个与对象1和对象3不同的交互。你显然不关心订单,所以将上半部或下三角半设置为NaN以进行下一步。假设欧几里德距离:

dists = sqrt(Xdiff.^2 + Ydiff.^2);
dists(tril(ones(numel(objects))==1)) = NaN;

第一行计算所有点对的欧几里德距离,我们使用tril提取由所有逻辑1组成的矩阵的下三角部分。提取此矩阵,我们使用此矩阵将矩阵的下半部分设置为NaN。这允许我们跳过我们不感兴趣的条目。注意我也将对角线设置为0,因为我们对一个对象与其自身的距离不感兴趣。

现在你终于到了这里,搜索那些< 300像素:

[I,J] = find(dists < 300);

IJ是行/列对,用于确定矩阵中哪些行和列具有值&lt; 300,所以在我们的例子中,数组中的每对IJ都会为您提供彼此接近的对象位置。

要最终确定正确的目标代码,您可以:

codes = [[objects(I).code].' [objects(J).code].'];

这使用IJ来访问逗号分隔列表中相似的对象的相应代码,并将它们并排放入N x 2矩阵中。因此,codes的每一行都为您提供满足距离要求的唯一对象对。

复制和粘贴:

points = reshape([objects.centre], 2, []);
X = points(1,:);
Y = points(2,:);
Xdiff = bsxfun(@minus, X.', X);
Ydiff = bsxfun(@minus, Y.', Y);
dists = sqrt(Xdiff.^2 + Ydiff.^2);
dists(tril(ones(numel(objects))==1)) = NaN;
[I,J] = find(dists < 300);    
codes = [[objects(I).code].' [objects(J).code].'];

玩具示例

以下是我们可以用来验证我们的内容是否正确的示例:

objects(1).centre = [1868 1236];
objects(2).centre = [2000 1000];
objects(3).centre = [1900 1300];
objects(4).centre = [3000 2000];
objects(1).code = 33;
objects(2).code = 34;
objects(3).code = 35;
objects(4).code = 99;

我用不同的质心和不同的代码初始化了4个对象。让我们看看dists数组在计算后给出的内容:

>> format long g
>> dists

dists =

                       NaN          270.407100498489          71.5541752799933          1365.69396278961
                       NaN                       NaN          316.227766016838           1414.2135623731
                       NaN                       NaN                       NaN          1303.84048104053
                       NaN                       NaN                       NaN                       NaN

我故意将最后一点比其他三点中的任何一点更远,以确保我们能够显示有些点不在其他点附近的情况。

正如您所看到的,点(1,2)和(1,3)彼此接近,这是我们完成其余代码时得到的结果。这对应于具有(33,34)和(33,35)配对的物体33,34和35。代码为34和35的点数稍微小一点,但它们仍然大于300像素阈值,因此它们不会计算:

>> codes

codes =

    33    34
    33    35

现在,如果你想以美化格式显示它,也许可以使用for循环:

for vec = codes.'
    fprintf('Object with code %d interacted with object with code %d\n', vec(1), vec(2));
end

这个for循环有点棘手。事实上,for loops can also accept matrices和索引变量从左到右一次为每个矩阵提供一列,这是一个鲜为人知的事实。因此,我转换了codes数组,以便每对唯一代码成为一列。我只是访问每列的第一个和第二个元素并将其打印出来。

我们得到:

Object with code 33 interacted with object with code 34
Object with code 33 interacted with object with code 35