翘曲图像在圆柱投影出现(Warp Image to Appear in Cylindrical Pr

2019-06-27 03:38发布

我想,因为它似乎是从一个气缸来的突起的方式翘曲的平面图像。

我有这样一个单位的形象:

我想它显示在2D图像是这样的:

我有点淘汰的几何预测。 我参观了像其他一些问题, 这可是我不明白我怎么会代表这些圆柱坐标(theta和RHO)为X,Y在笛卡尔(X,Y)平面坐标。 难道你们帮我一个煞费苦心的例子吗? 我编码它的iPhone和我没有使用任何第三方库像OpenCV的等

多谢。

Answer 1:

这是两个部分的答案,数学和代码

数学

我喜欢这个问题,因为涉及的投影是有趣的,但数学仍然可以通过手不会有太大困难得到解决。 首先,要了解到底为什么图像扭曲它的方式是很重要的。 假设我们有一个单位的形象有凹圆筒坐在它前面。

第一步是做正投影所述图像移动到所述弯曲表面。

然后将这些点投影与背透视到图像平面上。 请注意,在这种情况下,整个图像缩小因为气缸的所有部分具有比图像平面更大的Z坐标。 在你的情况下,汽缸接触的左,右边缘,以便不缩水发生像面。 当点被投射返回注意到他们不再形成在图像平面上的扁平线,有气缸随x变化的,因为z的曲线坐标。

第一招是我们真正想要向后代表这个过程。 你可能首先想到的是要采取的每一个像素在原始图像,并将其移动到您的新形象。 如果您在您的新图像的每个像素在那里出现在旧形象,并设置其颜色实际上,它的效果要好得多。 这意味着,你需要做三两件事。

  1. 设置您的圆柱体参数
  2. 投射来自照相机的射线,通过每一个点传递新的图像,并找到它的X,Y,Z在气缸坐标
  3. 使用的正投影来移动射线回图像平面(只是意味着下降的z分量)

藏在心里的轨迹可以是一个有点棘手,所以我会尝试使用一致的术语。 首先,我假设你要保证你的缸边缘处的触动你的形象。 如果这是真的,那么你可以选择2个自由参数是圆柱半径和焦距。

圆在ZX平面的方程为

x^2+(z-z0)^2 = r^2

假定圆的中心位于z轴上。 如果气缸的边缘将触碰其具有宽度w和焦距f,则图像平面的边缘

omega^2+(f-z0)^2 = r^2 //define omega = width/2, it cleans it up a bit
z0 = f-sqrt(r^2-omega^2)

现在我们知道我们继续从相机在XIM在XC步骤2,项目线,通过图像平面到气缸缸体的所有参数。 这里是术语的快速图。

我们知道线我们预计在原点开始,并在跨越XIM像面。 我们可以写出其方程

x = xim*z/f

因为我们希望在它穿过缸结合方程x坐标

xim^2*z^2/f^2 + z^2 - 2*z*z0 +z0^2 - r^2 = 0

您可以使用二次公式计算z和再插回线方程得到X。 这两种方案对应于两块地的线接触了一圈,因为我们只在图像平面后出现这种情况的一个感兴趣,一个将永远有一个较大的x坐标,使用-b +的sqrt(...) 。 然后

xc = xim*z/f;
yc = yim*z/f;

除去正投影的最后一步是易刚落z分量和你做。

我知道你说你不使用OpenCV的,但我会用它,在我的示范为图像容器。 所有的操作都通过像素的基础上完成的,因此不应该是你很难将它转换为对任何图像容器使用的是工作。 首先我做了,它把来自图像最终图像中的坐标在原始图像中的坐标功能。 OpenCV的把它的图像原点在左上角这就是为什么我开始通过减去W / 2和h / 2,并最终通过加回

cv::Point2f convert_pt(cv::Point2f point,int w,int h)
{
//center the point at 0,0
cv::Point2f pc(point.x-w/2,point.y-h/2);

//these are your free parameters
float f = w;
float r = w;

float omega = w/2;
float z0 = f - sqrt(r*r-omega*omega);

float zc = (2*z0+sqrt(4*z0*z0-4*(pc.x*pc.x/(f*f)+1)*(z0*z0-r*r)))/(2* (pc.x*pc.x/(f*f)+1)); 
cv::Point2f final_point(pc.x*zc/f,pc.y*zc/f);
final_point.x += w/2;
final_point.y += h/2;
return final_point;
}

现在,所有剩下的就是在旧的图像样品中的新图像的每一个点。 有这样做的很多方面,我做的最简单的一个,我知道在这里,双线性插值。 另外这只是设置为在灰度工作,使其在色彩的工作是简单的只是过程适用于所有3个通道。 我只是认为这将是一个更清楚一点这种方式。

for(int y = 0; y < height; y++)
{
    for(int x = 0; x < width; x++)
    {
        cv::Point2f current_pos(x,y);
        current_pos = convert_pt(current_pos, width, height);

        cv::Point2i top_left((int)current_pos.x,(int)current_pos.y); //top left because of integer rounding

        //make sure the point is actually inside the original image
        if(top_left.x < 0 ||
           top_left.x > width-2 ||
           top_left.y < 0 ||
           top_left.y > height-2)
        {
            continue;
        }

        //bilinear interpolation
        float dx = current_pos.x-top_left.x;
        float dy = current_pos.y-top_left.y;

        float weight_tl = (1.0 - dx) * (1.0 - dy);
        float weight_tr = (dx)       * (1.0 - dy);
        float weight_bl = (1.0 - dx) * (dy);
        float weight_br = (dx)       * (dy);

        uchar value =   weight_tl * image.at<uchar>(top_left) +
        weight_tr * image.at<uchar>(top_left.y,top_left.x+1) +
        weight_bl * image.at<uchar>(top_left.y+1,top_left.x) +
        weight_br * image.at<uchar>(top_left.y+1,top_left.x+1);

        dest_im.at<uchar>(y,x) = value;
    }
}

下面是对于f的样品输出= W / 2和r =瓦特



文章来源: Warp Image to Appear in Cylindrical Projection