使用给定点集扭曲图像的简单方法是什么?

时间:2016-01-19 18:55:17

标签: math graphics morphing

我想实现图像变形,我需要能够使用给定的点集和目标位置(它们将被拖拽")来使图像变形。我正在寻找一个简单易用的解决方案来完成工作,它不一定非常好或非常快。

这是我需要的一个例子:

让我们说我有一个图像和一组只有一个变形点[0.5,0.5],它的目标位于[0.6,0.5](或者我们可以说它的运动矢量是[0.1,0.0] ])。这意味着我想将图像的中心像素向右移动0.1。某些给定半径r中的相邻像素当然需要沿着#34;有点像这个像素。

我的想法就是这样做:

  1. 我将根据所提供的变形点设置将源图像位置映射到目标位置的功能。
  2. 然后我必须找到这个函数的反函数,因为我必须通过遍历目标像素并查看"其中点必须来自这个位置"来执行转换。
  3. 我在第1步的功能看起来像这样:

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

    ,其中

    • p0([x,y] vector)是变形点位置。
    • p1([x,y] vector)是源图像中的任何给定点。
    • p2([x,y] vector)是p1移动的位置。
    • s([x,y] vector)是变形点的运动矢量,表示在哪个方向以及p0的拖动距离。
    • r(标量)是半径,只是一些数字。

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

    • 如果有一个简单的解决方案来查找反函数,或
    • 如果有更好的功能,找到反函数很简单,或
    • 如果有一种完全不同的方法可以做到这一切很简单吗?

2 个答案:

答案 0 :(得分:2)

这是Python中的解决方案 - 我做了Yves Daoust推荐的内容,并且只是尝试使用forward函数作为反函数(切换源和目标)。我也略微改变了函数,改变指数和其他值会产生不同的结果。这是代码:

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")

morph

答案 1 :(得分:1)

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

你需要某种形式的双变量插值,看看径向基函数插值。它需要求解线性方程组。

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

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