将图像从笛卡尔坐标系转换为极坐标系

7

我正在尝试将一个有许多同心圆的图像从笛卡尔坐标系转换为极坐标系(新图像会是同心圆的线而不是实心圆,见下图),使用以下代码可以成功完成:

[r, c] = size(img);
r=floor(r/2);
c=floor(c/2);
[X, Y] = meshgrid(-c:c-1,-r:r-1);
[theta, rho] = cart2pol(X, Y); 
subplot(221), imshow(img), axis on;
hold on;
subplot(221), plot(xCenter,yCenter, 'r+');
subplot(222), warp(theta, rho, zeros(size(theta)), img);
view(2), axis square;

问题在于,我不明白为什么它会起作用?(显然不是我的代码)。我的意思是,当我使用cart2pol函数时,我根本没有使用图像,只是一些从meshgrid函数生成的向量x和y。另一个问题是,我希望以某种方式拥有一个新图像(不仅仅能够使用wrap功能绘制它),这个图像是原始图像,但根据theta和rho坐标重新排列像素。我甚至不确定如何询问这个问题,最终我想要一个矩阵形式的图像,以便我可以对每行求和并将该矩阵转换成列向量。
图片链接:example
1个回答

7
你可以将你的图像视为一个二维矩阵,其中每个像素具有X和Y坐标。
[(1,1)    (1,2)    (1,3)   ....   (1,c)]
[(2,1)    (2,2)    (2,3)   ....   (2,c)]
[(3,1)    (3,2)    (3,3)   ....   (3,c)]
[....     ....     ....    ....   .... ]
[(r,1)    (r,2)    (r,3)   ....   (r,c)]

在您发布的代码中,它将每个(X,Y)坐标映射到其相应的极坐标(R,theta),使用图像的中心floor(c/2)floor(r/2)作为参考点。
% Map pixel value at (1,1) to it's polar equivalent
[r,theta] = cart2pol(1 - floor(r/2),1 - floor(c/2));

所以,无论在图像中使用什么像素值作为(1,1),现在应该出现在您的新极坐标空间中的(r,theta)。需要注意的是,在执行此转换时,不需要关注图像中实际像素值的信息,而只需对图像中的每个像素执行此转换。
首先,我们要确定图像的中心位置:
[r, c] = size(img);
r = floor(r / 2);
c = floor(c / 2);

然后,我们计算出图像中每个点的(X,Y)坐标(在减去中心点之后)。
[X, Y] = meshgrid(-c:c-1,-r:r-1);

现在将所有这些笛卡尔坐标转换为极坐标。
[theta, rho] = cart2pol(X, Y); 

现在,warp 的作用只是在 (theta, rho) 对应的位置上显示 img 在 (X,Y) 处的值。
warp(theta, rho, zeros(size(theta)), img);

现在看起来你想要一个新的2D图像,其维度为[nTheta, nRho]。为此,你可以使用griddata函数将散点(theta,rho)图像(由上面的warp显示)进行插值,转换成规则网格。
% These is the spacing of your radius axis (columns)
rhoRange = linspace(0, max(rho(:)), 100);

% This is the spacing of your theta axis (rows)
thetaRange = linspace(-pi, pi, 100);

% Generate a grid of all (theta, rho) coordinates in your destination image
[T,R] = meshgrid(thetaRange, rhoRange);

% Now map the values in img to your new image domain
theta_rho_image = griddata(theta, rho, double(img), T, R);

看看所有的插值方法(interpolation methods),以确定哪种方法最适合您的情况。
还有一些其他问题(例如中心的四舍五入),导致结果略有不正确。下面提供了一个完整的工作示例。
% Create an image of circles
radii = linspace(0, 40, 10);

rows = 100;
cols = 100;
img = zeros(rows, cols);

for k = 1:numel(radii)
    t = linspace(0, 2*pi, 1000);
    xx = round((cos(t) * radii(k)) + (cols / 2));
    yy = round((sin(t) * radii(k)) + (rows / 2));

    toremove = xx > cols | xx < 1 | yy > rows | yy < 1;

    inds = sub2ind(size(img), xx(~toremove), yy(~toremove));

    img(inds) = 1;
end

[r,c] = size(img);
center_row = r / 2;
center_col = c / 2;

[X,Y] = meshgrid((1:c) - center_col, (1:r) - center_row);

[theta, rho] = cart2pol(X, Y);

rhoRange = linspace(0, max(rho(:)), 1000);
thetaRange = linspace(-pi, pi, 1000);

[T, R] = meshgrid(thetaRange, rhoRange);

theta_rho_image = griddata(theta, rho, double(img), T, R);

figure
subplot(1,2,1);
imshow(img);
title('Original Image')

subplot(1,2,2);
imshow(theta_rho_image);
title('Polar Image')

结果如下:

输入图像描述


谢谢,但是当我尝试添加代码去“创建”新图像时,我得到了以下错误: 使用 griddedInterpolant 时必须使用单个或双精度数组的样本值。interp2 中的错误 在 interp2>makegriddedinterp(第228行)中 F = griddedInterpolant(varargin {:});interp2 中的错误(第136行) F = makegriddedinterp(X,Y,V,method,extrap);scanPol 中的错误(第91行) theta_rho_image = interp2(theta,rho,img,T,R); - Rotem Elharar
@RotemElharar,这是因为为了执行插值,像素值必须转换为浮点数(它们可能当前是整数)。要做到这一点,只需将interp2(theta, rho, img, T, R)替换为interp2(theta, rho, double(img), T, R)即可。 - Suever
还是有些不对 :( 现在我得到了这个错误:Error using interp2>makegriddedinterp (line 237) 输入网格不是一个有效的 MESHGRID。在 interp2 中的错误 (第 136 行) F = makegriddedinterp(X, Y, V, method,extrap);在 scanPol 中的错误 (第 91 行) theta_rho_image = interp2(theta, rho, double(img), T, R); - Rotem Elharar
@RotemElharar 对此感到抱歉。Theta,rho点是分散的(不在规则网格上),因此我们必须使用griddata,它具有相同的格式但处理分散数据。 - Suever

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接