使用高度图扭曲图像?

我有一个图像的高度图,它告诉我每个像素在Z方向上的偏移量。 我的目标是只使用它的高度图平整扭曲的图像。

我会如何去做这件事? 如果有帮助,我知道相机的位置。


为此,我考虑假定每个像素都是平面上的一个点,然后根据我从高度图获得的Z值以及该翻译的垂直平移(假设您正在寻找在上面的点;转变将导致点从你的角度来回移动)。

从这个预测的转变中,我可以提取每个像素的X和Y偏移量,我可以将它提供给cv.Remap()

但我不知道如何通过OpenCV获得一个点的投影3D偏移量,更不用说构建一个偏移量图。


以下是我参考的图片:

校准图像扭曲的图像

我知道激光的角度(45度),并且从校准图像中,我可以很容易地计算出书的高度:

h(x) = sin(theta) * abs(calibration(x) - actual(x))

我对这两条线都做了这个,并使用这种方法线性插入两条线来生成一个曲面(Python代码,它在一个循环中):

height_grid[x][y] = heights_top[x] * (cv.GetSize(image)[1] - y) + heights_bottom[x] * y

我希望这有帮助 ;)


现在,这是我必须对图像进行解压的方法。 考虑到它的位置(以及相机的位置,旋转等),中间所有奇怪的东西都会将3D坐标投影到相机平面上:

class Point:
  def __init__(self, x = 0, y = 0, z = 0):
    self.x = x
    self.y = y
    self.z = z

mapX = cv.CreateMat(cv.GetSize(image)[1], cv.GetSize(image)[0], cv.CV_32FC1)
mapY = cv.CreateMat(cv.GetSize(image)[1], cv.GetSize(image)[0], cv.CV_32FC1)

c = Point(CAMERA_POSITION[0], CAMERA_POSITION[1], CAMERA_POSITION[2])
theta = Point(CAMERA_ROTATION[0], CAMERA_ROTATION[1], CAMERA_ROTATION[2])
d = Point()
e = Point(0, 0, CAMERA_POSITION[2] + SENSOR_OFFSET)

costx = cos(theta.x)
costy = cos(theta.y)
costz = cos(theta.z)

sintx = sin(theta.x)
sinty = sin(theta.y)
sintz = sin(theta.z)


for x in xrange(cv.GetSize(image)[0]):
  for y in xrange(cv.GetSize(image)[1]):

    a = Point(x, y, heights_top[x / 2] * (cv.GetSize(image)[1] - y) + heights_bottom[x / 2] * y)
    b = Point()

    d.x = costy * (sintz * (a.y - c.y) + costz * (a.x - c.x)) - sinty * (a.z - c.z)
    d.y = sintx * (costy * (a.z - c.z) + sinty * (sintz * (a.y - c.y) + costz * (a.x - c.x))) + costx * (costz * (a.y - c.y) - sintz * (a.x - c.x))
    d.z = costx * (costy * (a.z - c.z) + sinty * (sintz * (a.y - c.y) + costz * (a.x - c.x))) - sintx * (costz * (a.y - c.y) - sintz * (a.x - c.x))

    mapX[y, x] = x + (d.x - e.x) * (e.z / d.z)
    mapY[y, x] = y + (d.y - e.y) * (e.z / d.z)


print
print 'Remapping original image using map...'

remapped = cv.CreateImage(cv.GetSize(image), 8, 3)
cv.Remap(image, remapped, mapX, mapY, cv.CV_INTER_LINEAR)

这现在变成了一大串图像和代码......无论如何,这个代码块需要我7分钟才能在18MP相机图像上运行; 这太长了,最后,这种方法对图像没有任何影响(每个像素的偏移量是<< 1 )。

有任何想法吗?


我最终实现了我自己的解决方案:

for x in xrange(cv.GetSize(image)[0]):
  for y in xrange(cv.GetSize(image)[1]):

    a = Point(x, y, heights_top[x / 2] * (cv.GetSize(image)[1] - y) + heights_bottom[x / 2] * y)
    b = Point()

    d.x = costy * (sintz * (a.y - c.y) + costz * (a.x - c.x)) - sinty * (a.z - c.z)
    d.y = sintx * (costy * (a.z - c.z) + sinty * (sintz * (a.y - c.y) + costz * (a.x - c.x))) + costx * (costz * (a.y - c.y) - sintz * (a.x - c.x))
    d.z = costx * (costy * (a.z - c.z) + sinty * (sintz * (a.y - c.y) + costz * (a.x - c.x))) - sintx * (costz * (a.y - c.y) - sintz * (a.x - c.x))

    mapX[y, x] = x + 100.0 * (d.x - e.x) * (e.z / d.z)
    mapY[y, x] = y + 100.0 * (d.y - e.y) * (e.z / d.z)


print
print 'Remapping original image using map...'

remapped = cv.CreateImage(cv.GetSize(image), 8, 3)
cv.Remap(image, remapped, mapX, mapY, cv.CV_INTER_LINEAR)

这(缓慢)重新映射每个像素使用cv.Remap函数,这似乎是一种工作...


基于距相机距离的失真仅在透视投影中发生。 如果具有像素的(x,y,z)位置,则可以使用摄像机的投影矩阵将像素重新投影到世界空间中。 利用这些信息,您可以以正交方式呈现像素。 但是,由于原始透视投影,您可能会丢失数据。


将你的场景分开如下:

  • 你有一个未知的位图图像I (x,y) - >(r,g,b)
  • 你有一个已知的高度场H (x,y) - > h
  • 你有一个相机变换C (x,y,z) - >(u,v),它将场景投影到屏幕平面
  • 请注意,相机变换会丢弃信息(您无法获得每个屏幕像素的深度值)。 你也可以在屏幕上重叠一些场景,在这种情况下只显示最前面的部分 - 其余部分将被丢弃。 所以一般来说这不是完全可逆的。

  • 你有一个截屏S(U,V),其是C(X,Y,H(X,Y))为X,Y在的结果
  • 要生成的屏幕截图S '(U',V'),其是C(X,Y,0)为X,Y在的结果
  • 有两种明显的方法可以解决这个问题。 两者都依赖于具有相机变换的准确值。

  • 光线投射:对于S中的每个像素,将光线投射回场景中。 找出它到达高度场的地方; 这给了你在原始图像I中的(x,y),屏幕像素为你提供了那个点的颜色。 一旦你有尽可能多的 ,你可以恢复,重新改造它找到S”。

  • 双重渲染:对于我中的每个x,y,找到(u,v)和(u',v')。 从S (u,v)中取像素颜色并将其复制到S' (u',v')。

  • 这两种方法都会有抽样问题,这些问题可以通过超级采样或插值来获得帮助 方法1将在图像的遮挡区域留下空白空间,方法2将从第一个表面“投影”。

    编辑:

    我假设你的意思是一个CG风格的高度场,其中S中的每个像素都直接在S'中的相应位置的上方; 但这不是页面如何在表面上打印。 页面固定在脊柱上,无弹力 - 抬起页面的中心会将自由边缘拉向脊柱。

    根据您的样本图像,您必须扭转这种累计拉动 - 检测脊椎中心线的位置和方向,并逐步向左和向右移动,找到每个垂直条的顶部和底部的高度变化,计算结果方面缩小和倾斜,并将其反转以重新创建原始平面页面。

    链接地址: http://www.djcxy.com/p/5185.html

    上一篇: Distorting an image using a height map?

    下一篇: How do I implement MVCC?