我目前正在尝试使用一组世界点(X)及其对应的图像点(x)来计算相机矩阵P.但是,在测试结果时,P(3 x 4相机矩阵)乘以世界点不会给我正确的相应图像点。但是,只有第一列PX = x。另一列不会返回近似图像点。
代码:
X = [1 2 3; 4 5 6; 7 8 9; 1 1 1];
x = [3 2 1; 6 5 4; 1 1 1];
[mX, nX] = size(X);
[mx, nx] = size(x);
for i = 0:(nX-1)
XX{i+1} = transpose(X(1+i: 4+i));
end
for i = 0:(nx-1)
xx{i+1} = transpose(x(i+1:3+i));
end
%TODO - normalization
A = [];
%construct matrix
for i = 1:nX
A = [A; zeros(1,4) -1*(xx{i}(3)*transpose(XX{i})) xx{i}(2)*transpose(XX{i})];
A = [A; xx{i}(3)*transpose(XX{i}) zeros(1,4) -1*xx{i}(1)*transpose(XX{i})];
end
%using svd to solve for non zero solution
[u s v] = svd(A);
p = v(:, size(v,2));
p = reshape(p, 4,3)';
第一列的输出,效果很好:
>> p*XX{1}
ans =
0.0461
0.0922
0.0154
>> ans/0.0154
ans =
2.9921
5.9841
0.9974
>> xx{1}
ans =
3
6
1
第二列的输出,不起作用:
>> p*XX{2}
ans =
0.5202
0.0867
0.1734
>> ans/0.1734
ans =
2.9999
0.5000
1.0000
>> xx{2}
ans =
6
1
2
顺便说一下,我被告知在计算相机矩阵之前需要对世界点和图像点进行标准化。我还没有完成这一步,也不知道该怎么做。如果这导致了问题,请解释可以做什么。先感谢您。
答案 0 :(得分:0)
这是因为您没有正确地索引到矩阵中。您正在使用线性索引来访问矩阵的每一列。在这种情况下,您的for
循环需要独立访问每个列。因此,for
循环的每次迭代必须访问3D点的4个元素组和2D点的3个元素组。
因此,您只需要为for
循环执行此操作:
for i = 0:(nX-1)
XX{i+1} = transpose(X(4*i + 1 : 4*(i + 1)));
end
for i = 0:(nx-1)
xx{i+1} = transpose(x(3*i + 1 : 3*(i + 1)));
end
在此之后,代码应该没有问题。为了验证,我们可以遍历每个3D点,并在您使用单元格时确定其2D等效值:
out = zeros(size(xx)); % Declare output matrix
for ii = 1 : numel(XX) % For each 3D point...
out(:,ii) = p * XX{ii}; % Transform the point
out(:,ii) = out(:,ii) / out(end,ii); % Normalize
end
我们得到:
>> out
out =
3.0000 2.0000 1.0000
6.0000 5.0000 4.0000
1.0000 1.0000 1.0000
与您的x
比较:
>> x
x =
3 2 1
6 5 4
1 1 1
如果我可以提出建议,请不要在这里使用单元格阵列。您可以创建方程矩阵,以便使用矢量化求解。具体来说,您可以直接创建矩阵A
而不需要任何for
循环:
A = [zeros(N, 4) -X.' bsxfun(@times, x(2,:).', X.');
X.' zeros(N, 4) bsxfun(@times, -x(1,:).', X.')];
如果您拥有MATLAB R2016b及更高版本,则可以通过内部广播来实现:
A = [zeros(N, 4) -X.' x(2,:).' .* X.';
X.' zeros(N, 4) -x(1,:).' .* X.']
请注意,由于矢量化,您将看到与原始矩阵A
相比较的行被洗牌。因为我们正在求解矩阵A
的零空间,所以对行进行混洗不起作用。因此,您的代码可以简化为:
X = [1 2 3; 4 5 6; 7 8 9; 1 1 1];
x = [3 2 1; 6 5 4; 1 1 1];
A = [zeros(N, 4) -X.' bsxfun(@times, x(2,:).', X.');
X.' zeros(N, 4) bsxfun(@times, -x(1,:).', X.')];
% Use this for MATLAB R2016b and up
% A = [zeros(N, 4) -X.' x(2,:).' .* X.';
% X.' zeros(N, 4) -x(1,:).' .* X.']
[u, s, v] = svd(A);
p = v(:, end);
p = reshape(p, 4, 3).';
要最终计算输出矩阵,您可以使用简单矩阵乘法。您使用单元格的事实要求您必须使用for
循环,并且使用矩阵乘法更快地执行此操作:
out = p * X;
然后,您可以获取结果的最后一行,并将此行中的每一行划分。
out = bsxfun(@rdivide, out, out(end,:));
再次使用MATLAB R2016b及以上版本,您可以这样做:
out = out ./ out(end,:);