如何在 Matlab 中转换传输点?
How imwarp transfer points in Matlab?
我正在使用 Matlab 将图像转换为目标图像。我有几何变换(tform)。
例如这是我的 'tform':
1.0235 0.0022 -0.0607 0
-0.0276 1.0002 0.0089 0
-0.0170 -0.0141 1.1685 0
12.8777 5.0311 -70.0325 1.0000
在Matlab2013中,使用imwarp可以轻松做到:
%nii = 3D MR Image
I = nii.img;
dii=nii.hdr.dime.pixdim(2:4);
Rfixed=imref3d(size(I),dii(2),dii(1),dii(3));
new_img= imwarp(old_img, Rfixed, tform, 'OutputView', Rfixed);
使用 imwarp(图像中的红肺)结果非常完美
我需要知道 imwarp 是如何工作的,然后我写了我自己的函数
function [new_img] = aff3d(old_img, tform, range_x, range_y, range_z)
[U, V, W] = ndgrid(range_x, range_y, range_z);
xyz = [reshape(U,[],1)';reshape(V,[],1)';reshape(W,[],1)'];
xyz = [xyz; ones(1,size(xyz,2))];
uvw = tform.T * xyz;
% avoid homogeneous coordinate
uvw = uvw(1:3,:)';
xi = reshape(uvw(:,1), length(range_x),length(range_y),length(range_z));
yi = reshape(uvw(:,2), length(range_x),length(range_y),length(range_z));
zi = reshape(uvw(:,3), length(range_x),length(range_y),length(range_z));
old_img = single(old_img);
new_img = interp3(old_img,yi,xi,zi,'linear');
ii = find(isnan(new_img));
if(~isempty(ii))
new_img(ii) = 0;
end
end
我的函数 () 的结果与 imwarp 输出不匹配(红肺未定位在正确的位置),有人可以帮助我吗?
按照 Ander 的建议,尝试乘以逆变换:
Tinv = tform.invert();
TinvMatrix = Tinv.T;
因此您的代码将变为:
function [new_img] = aff3d(old_img, tform, range_x, range_y, range_z)
[U, V, W] = ndgrid(range_x, range_y, range_z);
xyz = [reshape(U,[],1)';reshape(V,[],1)';reshape(W,[],1)'];
xyz = [xyz; ones(1,size(xyz,2))];
tformInv = invert(tform);
uvw = tformInv.T * xyz;
% avoid homogeneous coordinate
uvw = uvw(1:3,:)';
xi = reshape(uvw(:,1), length(range_x),length(range_y),length(range_z));
yi = reshape(uvw(:,2), length(range_x),length(range_y),length(range_z));
zi = reshape(uvw(:,3), length(range_x),length(range_y),length(range_z));
old_img = single(old_img);
new_img = interp3(old_img,yi,xi,zi,'linear');
ii = find(isnan(new_img));
if(~isempty(ii))
new_img(ii) = 0;
end
end
在您的代码中,您在 old_img 中进行插值以尝试找到已扭曲的 new_img。这意味着您要做的是使用从输出图像 space 映射到输入图像 space 的逆映射。您似乎是在使用点的前向映射对旧图像进行插值,这是不正确的。
http://blogs.mathworks.com/steve/2006/04/28/spatial-transforms-forward-mapping/
http://blogs.mathworks.com/steve/2006/05/05/spatial-transformations-inverse-mapping/
我会使用上面的链接来查看正向映射和反向映射。 IMWARP 使用逆映射。
造成混淆的部分原因是,当人们想到几何变换时,他们通常会根据点如何从 old_image 映射到 new_image 的正向映射来思考。为此,affine3d变换的"T"属性用前向映射来表述。
当需要在软件中实现几何变换时,easier/better 需要根据逆映射来实现。这就是 imwarp 所做的,这就是为什么在尝试重现 imwarp 行为时需要反转转换的原因。如果您阅读了关于逆向映射的博客 post,就会发现该算法正是 IMWARP 正在做的事情。
您唯一需要解决的问题是 IMWARP 在非默认坐标系(使用非默认空间参考对象)中执行的操作,以防 WorldLimits 不能被离散的像素网格整除。这种行为是任意的,没有 "right" 行为。 IMWARP 行为是为了遵守请求的分辨率 (PixelExtentInWorld) 并在这种情况下稍微调整世界限制。
我正在使用 Matlab 将图像转换为目标图像。我有几何变换(tform)。
例如这是我的 'tform':
1.0235 0.0022 -0.0607 0
-0.0276 1.0002 0.0089 0
-0.0170 -0.0141 1.1685 0
12.8777 5.0311 -70.0325 1.0000
在Matlab2013中,使用imwarp可以轻松做到:
%nii = 3D MR Image
I = nii.img;
dii=nii.hdr.dime.pixdim(2:4);
Rfixed=imref3d(size(I),dii(2),dii(1),dii(3));
new_img= imwarp(old_img, Rfixed, tform, 'OutputView', Rfixed);
使用 imwarp(图像中的红肺)结果非常完美
我需要知道 imwarp 是如何工作的,然后我写了我自己的函数
function [new_img] = aff3d(old_img, tform, range_x, range_y, range_z)
[U, V, W] = ndgrid(range_x, range_y, range_z);
xyz = [reshape(U,[],1)';reshape(V,[],1)';reshape(W,[],1)'];
xyz = [xyz; ones(1,size(xyz,2))];
uvw = tform.T * xyz;
% avoid homogeneous coordinate
uvw = uvw(1:3,:)';
xi = reshape(uvw(:,1), length(range_x),length(range_y),length(range_z));
yi = reshape(uvw(:,2), length(range_x),length(range_y),length(range_z));
zi = reshape(uvw(:,3), length(range_x),length(range_y),length(range_z));
old_img = single(old_img);
new_img = interp3(old_img,yi,xi,zi,'linear');
ii = find(isnan(new_img));
if(~isempty(ii))
new_img(ii) = 0;
end
end
我的函数 (
按照 Ander 的建议,尝试乘以逆变换:
Tinv = tform.invert();
TinvMatrix = Tinv.T;
因此您的代码将变为:
function [new_img] = aff3d(old_img, tform, range_x, range_y, range_z)
[U, V, W] = ndgrid(range_x, range_y, range_z);
xyz = [reshape(U,[],1)';reshape(V,[],1)';reshape(W,[],1)'];
xyz = [xyz; ones(1,size(xyz,2))];
tformInv = invert(tform);
uvw = tformInv.T * xyz;
% avoid homogeneous coordinate
uvw = uvw(1:3,:)';
xi = reshape(uvw(:,1), length(range_x),length(range_y),length(range_z));
yi = reshape(uvw(:,2), length(range_x),length(range_y),length(range_z));
zi = reshape(uvw(:,3), length(range_x),length(range_y),length(range_z));
old_img = single(old_img);
new_img = interp3(old_img,yi,xi,zi,'linear');
ii = find(isnan(new_img));
if(~isempty(ii))
new_img(ii) = 0;
end
end
在您的代码中,您在 old_img 中进行插值以尝试找到已扭曲的 new_img。这意味着您要做的是使用从输出图像 space 映射到输入图像 space 的逆映射。您似乎是在使用点的前向映射对旧图像进行插值,这是不正确的。
http://blogs.mathworks.com/steve/2006/04/28/spatial-transforms-forward-mapping/ http://blogs.mathworks.com/steve/2006/05/05/spatial-transformations-inverse-mapping/
我会使用上面的链接来查看正向映射和反向映射。 IMWARP 使用逆映射。
造成混淆的部分原因是,当人们想到几何变换时,他们通常会根据点如何从 old_image 映射到 new_image 的正向映射来思考。为此,affine3d变换的"T"属性用前向映射来表述。
当需要在软件中实现几何变换时,easier/better 需要根据逆映射来实现。这就是 imwarp 所做的,这就是为什么在尝试重现 imwarp 行为时需要反转转换的原因。如果您阅读了关于逆向映射的博客 post,就会发现该算法正是 IMWARP 正在做的事情。
您唯一需要解决的问题是 IMWARP 在非默认坐标系(使用非默认空间参考对象)中执行的操作,以防 WorldLimits 不能被离散的像素网格整除。这种行为是任意的,没有 "right" 行为。 IMWARP 行为是为了遵守请求的分辨率 (PixelExtentInWorld) 并在这种情况下稍微调整世界限制。