2016-01-19 2 views
1

Je voudrais implémenter le morphing d'image, pour lequel j'ai besoin de pouvoir déformer l'image avec un ensemble donné de points et leurs positions de destination (où ils seront "traînés"). Je suis à la recherche d'une solution simple et facile qui fait le travail, il ne doit pas être beau ou être extrêmement rapide.Qu'est-ce qu'un moyen simple de déformer une image avec un ensemble donné de points?

Voici un exemple ce que je dois:

Disons que j'ai une image et un ensemble d'un seul point de déformante [0.5,0.5] qui aura sa destination à [0.6,0.5] (ou nous pouvons disons que son vecteur de mouvement est [0.1,0.0]). Cela signifie que je veux déplacer le pixel très central de l'image de 0,1 vers la droite. Les pixels voisins d'un rayon donné r doivent bien sûr être "traînés" un peu avec ce pixel.

Mon idée était de le faire comme ceci:

  1. Je vais faire une fonction cartographie des positions d'image source à des postes de destination en fonction de l'ensemble de points de déformation prévu.
  2. Je devrai alors trouver la fonction inverse de cette fonction, car je dois effectuer la transformation en passant par les pixels de destination et en voyant "d'où le point devait venir pour arriver à cette position".

Ma fonction de l'étape 1 ressemblait à ceci:

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

  • p0 (vecteur [x, y]) est la position du point de déformation.
  • p1 (vecteur [x, y]) est un point donné dans l'image source.
  • p2 (vecteur [x, y]) est la position où p1 sera déplacée. (Vecteur [x, y]) est un vecteur de mouvement du point de déformation et indique dans quelle direction et dans quelle mesure p0 sera traîné.
  • r (scalaire) est le rayon, juste un nombre.

J'ai problème avec le numéro de l'étape 2. Le calcul de la fonction inverse semble un peu trop complexe pour moi et je me demande donc:

  • S'il y a une solution facile pour trouver la fonction inverse, ou
  • s'il y a une meilleure fonction pour laquelle trouver la fonction inverse est simple, ou
  • s'il y a une manière entièrement différente de faire tout cela qui est simple?

Répondre

1

Vous n'avez pas besoin de construire la fonction directe et de l'inverser. Calculez directement la fonction inverse en inversant les rôles des points source et destination.

Vous avez besoin d'une forme d'interpolation bivariée, regardez l'interpolation de la fonction de base radiale. Cela nécessite de résoudre un système linéaire d'équations. La pondération à distance inverse (similaire à votre proposition) est la plus facile à implémenter mais je crains qu'elle ne donne des résultats décevants.

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

0

est ici la solution en Python - je l'ai fait ce que Yves Daoust recommandé et simplement essayé d'utiliser la fonction avant que la fonction inverse (commutation de la source et la destination). J'ai également modifié légèrement la fonction, en changeant les exposants et d'autres valeurs produisent des résultats différents. Voici le code:

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