【问题标题】:What's a simple way of warping an image with a given set of points?用给定的一组点扭曲图像的简单方法是什么?
【发布时间】:2016-04-25 09:33:01
【问题描述】:

我想实现图像变形,为此我需要能够使用给定的一组点及其目标位置(它们将被“拖动”的位置)对图像进行变形。我正在寻找一种简单易行的解决方案来完成工作,它不需要看起来很棒或非常快。

这是我需要的示例:

假设我有一个图像和一组只有一个变形点 [0.5,0.5],其目的地是 [0.6,0.5](或者我们可以说它的运动矢量是 [0.1,0.0])。这意味着我想将图像的中心像素向右移动 0.1。某些给定半径 r 中的相邻像素当然需要与该像素一起“拖动”一点。

我的想法是这样做:

  1. 我将创建一个函数,根据提供的变形点集将源图像位置映射到目标位置。
  2. 然后我必须找到该函数的反函数,因为我必须通过遍历目标像素并查看“点必须从哪里到达这个位置”来执行转换。

第 1 步的函数如下所示:

p2 = p1 + ( 1 / ( (distance(p1,p0) / r)^2 + 1 ) ) * s

在哪里

  • p0([x,y]向量)为变形点位置。
  • p1([x,y] 向量)是源图像中的任意给定点。
  • p2([x,y] 向量)是将 p1 移动到的位置。
  • s ([x,y] vector) 是变形点的运动向量,表示p0将被拖动到哪个方向和多远。
  • r(标量)是半径,只是一些数字。

我对第 2 步有疑问。反函数的计算对我来说似乎有点太复杂了,所以我想知道:

  • 如果找到反函数的简单解决方案,或
  • 如果有一个更好的函数可以简单地找到反函数,或者
  • 如果有一种完全不同的简单方法来完成这一切?

【问题讨论】:

    标签: math graphics morphing


    【解决方案1】:

    这是 Python 中的解决方案 - 我做了Yves Daoust 推荐的操作,只是尝试使用正向函数作为逆向函数(切换源和目标)。我还稍微改变了函数,改变指数和其他值会产生不同的结果。代码如下:

    from PIL import Image
    import math
    
    def vector_length(vector):
      return math.sqrt(vector[0] ** 2 + vector[1] ** 2)
    
    def points_distance(point1, point2):
      return vector_length((point1[0] - point2[0],point1[1] - point2[1]))
    
    def clamp(value, minimum, maximum):
      return max(min(value,maximum),minimum)
    
    ## Warps an image accoording to given points and shift vectors.
    #  
    #  @param image input image
    #  @param points list of (x, y, dx, dy) tuples
    #  @return warped image
    
    def warp(image, points):
      result = img = Image.new("RGB",image.size,"black")
    
      image_pixels = image.load()
      result_pixels = result.load()
    
      for y in range(image.size[1]):
        for x in range(image.size[0]):
    
          offset = [0,0]
    
          for point in points:
            point_position = (point[0] + point[2],point[1] + point[3])
            shift_vector = (point[2],point[3])
    
            helper = 1.0 / (3 * (points_distance((x,y),point_position) / vector_length(shift_vector)) ** 4 + 1)
    
            offset[0] -= helper * shift_vector[0]
            offset[1] -= helper * shift_vector[1]
    
          coords = (clamp(x + int(offset[0]),0,image.size[0] - 1),clamp(y + int(offset[1]),0,image.size[1] - 1))
    
          result_pixels[x,y] = image_pixels[coords[0],coords[1]]
    
      return result
    
    image = Image.open("test.png")
    image = warp(image,[(210,296,100,0), (101,97,-30,-10), (77,473,50,-100)])
    image.save("output.png","PNG")
    

    【讨论】:

      【解决方案2】:

      您不需要构造直接函数并将其反转。通过交换源点和目标点的角色直接计算反函数。

      您需要某种形式的二元插值,看看径向基函数插值。它需要求解一个线性方程组。

      反向距离加权(类似于您的建议)是最容易实现的,但我担心它会产生令人失望的结果。

      https://en.wikipedia.org/wiki/Multivariate_interpolation#Irregular_grid_.28scattered_data.29

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-05-12
        • 1970-01-01
        • 2015-11-22
        • 1970-01-01
        • 2021-03-07
        • 1970-01-01
        相关资源
        最近更新 更多