极性的快速算法 - >笛卡尔转换

时间:2009-08-17 18:36:16

标签: algorithm image reformat

我在极地网格上有一个图像。这个图像应该转换成笛卡尔网格,但我所知道的唯一算法对此来说真的很慢。现在我使用笛卡尔网格,对于每个点我找到r和theta值,然后我查看两个向量以找到由下式定义的最小错误:

min {(th_vec - theta)^ 2 +(range - r)^ 2}

这给出了外部嵌套for循环内部的嵌套for循环,因此我的复杂度为O(N ^ 4)。 512x512图像使用整分钟完成。当然,这样的复杂性无法使用,所以我想知道是否有人知道更快的算法来做到这一点?

我有图像和两个向量。图像的X轴是角度,而图像的Y轴是距中心的长度。角度始终为0-2pi,范围从0到r_max。

提前谢谢。

编辑:范围从0到r_max,而不是-r_max到之前的r_max。我看到有一些误解。我使用了正常的,反向的转换;


r=sqrt(x^2 + y^2);
theta=atan2(y,x);

问题在于我必须首先将x和y值转换为x'和y'值,因为网格在结果图像中从-r_max到r_max,但在数据中以像素为单位。所以我有一个512x512的图像,但r_max可能是3.512。所以我必须将每个像素值转换为网格值,然后找到r和theta值。当我找到r和theta值时,我必须运行两个矢量range和th_vec,以找到原始图像中匹配的像素:

min {(range-r)^ 2 +(th_vec-theta)^ 2}

这给了我O(n ^ 4)的复杂度,因为th_vec和范围向量与图像的大小相同。因此,如果我有一个512x512元素的方阵,我必须运行68 719 476 736元素,这很慢。所以我想知道是否有更快的算法?我不能改变输入数据,所以据我所知,如果你不从三角测量和东西开始,这是唯一的方法,但这在内存时是昂贵的。

7 个答案:

答案 0 :(得分:10)

怎么样

x=r*cos(angle)
y=r*sin(angle)

这是从极地转换为笛卡尔的标准方式,除非你打算使用某种表查找,否则实际上没有更快的选择。

编辑:争吵有一个好点。如果您尝试将极坐标I(angle, r)中的图像转换为笛卡尔坐标I_new(x, y)中的图像,那么您最好使用逆变换,如下所示:

for x=1,...,width
    for y=1,...,height
        angle=atan2(y, x)
        r=sqrt(x^2+y^2)
        I_new(x, y)=I(angle, r)
    end
end

通常,angler不会是整数,因此您必须在图像I中进行某种插值。最简单的方法就是围绕angler;这会给你nearest-neighbour interpolation。如果您需要更高质量,请尝试更复杂的插值类型,例如bilinearbicubic插值。

答案 1 :(得分:5)

您可以遍历极坐标图像中的每个像素,然后在笛卡尔图像平面中渲染生成的弧段:

polar to cartesian conversion http://img24.imageshack.us/img24/4635/polartocartesian.png

const float dR = 2*r_max / polar_image_height;
const float dA = 2*pi / polar_image_width;

float angle;
float radius;
for (int polar_x = 0; polar_x < polar_image_width; polar_x++)
{
    for (int polar_y = 0; polar_y < polar_image_height; polar_y++)
    {
        angle = polar_x * dA;
        radius = polar_y * dR - r_max;
        DrawArcSection(radius, radius+dR, angle, angle+dA);
    }
}

许多绘图库都有用于绘制弧形截面的内置函数,但您总是可以使用简单的多边形来近似它:

void DrawArcSection(float minRadius, float maxRadius,
                    float minAngle, float maxAngle)
{
    point P1 = MakePoint(minRadius * cos(minAngle) + image_width/2,
                         minRadius * sin(minAngle) + image_height/2);
    point P2 = MakePoint(minRadius * cos(maxAngle) + image_width/2,
                         minRadius * sin(maxAngle) + image_height/2);
    point P3 = MakePoint(maxRadius * cos(minAngle) + image_width/2,
                         maxRadius * sin(minAngle) + image_height/2);
    point P3 = MakePoint(maxRadius * cos(maxAngle) + image_width/2,
                         maxRadius * sin(maxAngle) + image_height/2);

    DrawPolygon(P1, P2, P3, P4);
}

答案 2 :(得分:3)

如果您不关心平滑,为什么不计算每个目的地笛卡尔像素坐标的极坐标并读取颜色值?如果您需要帮助,请参阅http://en.wikipedia.org/wiki/Polar_coordinate_system#Converting_between_polar_and_Cartesian_coordinates

答案 3 :(得分:1)

如果您的网格相对于极坐标进行了均匀分割,那么如果您利用与(r,theta)的最近点将是其中一个的事实,您的算法可以减少到O(N ^ 2)。包含它的网格元素的四个角。

在更一般的情况下,网格是r和theta维度的任意分区的乘积,如果你必须搜索点的位置,它可能会增长到O((N log N)^ 2)每个分区。但是,如果系统地构建分区,您应该能够回到O(N ^ 2)。

答案 4 :(得分:0)

内存失败,但可能存在涉及FFT的此算法的快速版本。曾几何时我参加了医学成像课程,看起来这种东西在不进行CT扫描变形/光栅化时突然出现。要搜索的一些关键字是氡变换,滤波反投影算法和CT扫描。我在维基百科上简要地查看了这些内容并没有跳出来,但也许更彻底的审查会变成金币。

答案 5 :(得分:0)

O(N 2 log(N))算法:

  • 阵列S将用于每个笛卡尔坐标的最近源(极坐标)坐标。
  • S开始填充“未初始化的”值。 (Python:无,Haskell:没什么,等等。)
  • O(N 2 ) - 迭代所有极坐标。
    • 转换为笛卡尔坐标
    • 在目标图片中查找最近的笛卡尔坐标。 (通过四舍五入和应用边界)
    • 使用此坐标
    • 填写S中的相关单元格
  • O(N 2 log(N)) - 执行修改后的Dijkstra算法,如下所述:
    • 我们的搜索算法的“图表”如下:
      • S的所有单元格都是节点
      • 一个小区的邻居是国际象棋中的国王可以从中移动的
    • 如果没有初始化,则单元格的“得分”是无限的,与未触及的单元的距离是无限的 极地坐标的笛卡尔坐标指向
    • 当更新单元格N的邻居时,我们将单元格N的值放入其中(但在Dijkstra中,只有当它的得分高于其当前得分时才会这样)
    • 起点是如上所述初始化的数组

答案 6 :(得分:0)

如果您的所有图像都是512x512,那么我会使用查找表将极坐标图像中的一组加权像素映射到笛卡尔图像。这是预先做了很多工作,但最终计算结果为O(n ^ 2)。如果LUT不是一个选项,那么我会使用:

x=r*cos(angle)
y=r*sin(angle)

在极坐标图像中的每个像素上将其映射到笛卡尔图像中的“a”像素,其中输出像素是落在其上的所有输入像素的平均值。然后应用重复的扩张,直到没有未初始化的像素为止。对于扩张,您使用3x3结构元素,并且仅将输出像素的值替换为中心像素的值(如果之前没有值)。然后,作为最终测量,对整个图像应用高斯滤波器以平滑硬边缘。这是我能想到的最快的方法,可以在合理的时间内产生令人愉悦的图像。