Существует ли библиотека деформирования / морфинга изображений для python с контролируемыми точками? - PullRequest
7 голосов
/ 21 февраля 2011

Вы будете делать снимки и отмечать определенные точки (например, отмечать область вокруг глаз, носа, рта и т. Д.), А затем преобразовывать их в точки, помеченные в другом изображении. Что-то вроде:

transform(original_image, marked_points_in_the_original, marked_points_in_the_reference)

Кажется, я не могу найти алгоритм, описывающий его, и не могу найти никаких библиотек с ним. Я тоже хочу сделать это сам, если смогу найти хороший / легкий материал для этого. Я знаю, что это возможно, так как я видел некоторые неполные (на самом деле не объясняю, как это сделать) .pdfs на Google с ним.

Вот пример отмеченных точек и преобразования, поскольку вы просили разъяснений. Хотя этот человек не использует 2 человек, как я сказал ранее.


Редактировать: мне удалось заставить работать метод im.transform, но аргумент - это список ((box_x, box_y, box_width, box_height), (x0, y0, x1, y1, x2, y2, x3, y3)), где первая точка - NW, второй SW, третий NE и четвертый SE. Насколько я мог судить, (0, 0) - самая левая верхняя часть экрана. Если я все сделал правильно, то этот метод на самом деле не делает то, что мне нужно.

Ответы [ 3 ]

8 голосов
/ 20 мая 2016

Пример кода, предоставленного Blender, не работает для меня. Также документация PIL для im.transform неоднозначна. Поэтому я копаюсь в исходном коде PIL и, наконец, выясняю, как использовать интерфейс. Вот мое полное использование:

import numpy as np
from PIL import Image

def quad_as_rect(quad):
    if quad[0] != quad[2]: return False
    if quad[1] != quad[7]: return False
    if quad[4] != quad[6]: return False
    if quad[3] != quad[5]: return False
    return True

def quad_to_rect(quad):
    assert(len(quad) == 8)
    assert(quad_as_rect(quad))
    return (quad[0], quad[1], quad[4], quad[3])

def rect_to_quad(rect):
    assert(len(rect) == 4)
    return (rect[0], rect[1], rect[0], rect[3], rect[2], rect[3], rect[2], rect[1])

def shape_to_rect(shape):
    assert(len(shape) == 2)
    return (0, 0, shape[0], shape[1])

def griddify(rect, w_div, h_div):
    w = rect[2] - rect[0]
    h = rect[3] - rect[1]
    x_step = w / float(w_div)
    y_step = h / float(h_div)
    y = rect[1]
    grid_vertex_matrix = []
    for _ in range(h_div + 1):
        grid_vertex_matrix.append([])
        x = rect[0]
        for _ in range(w_div + 1):
            grid_vertex_matrix[-1].append([int(x), int(y)])
            x += x_step
        y += y_step
    grid = np.array(grid_vertex_matrix)
    return grid

def distort_grid(org_grid, max_shift):
    new_grid = np.copy(org_grid)
    x_min = np.min(new_grid[:, :, 0])
    y_min = np.min(new_grid[:, :, 1])
    x_max = np.max(new_grid[:, :, 0])
    y_max = np.max(new_grid[:, :, 1])
    new_grid += np.random.randint(- max_shift, max_shift + 1, new_grid.shape)
    new_grid[:, :, 0] = np.maximum(x_min, new_grid[:, :, 0])
    new_grid[:, :, 1] = np.maximum(y_min, new_grid[:, :, 1])
    new_grid[:, :, 0] = np.minimum(x_max, new_grid[:, :, 0])
    new_grid[:, :, 1] = np.minimum(y_max, new_grid[:, :, 1])
    return new_grid

def grid_to_mesh(src_grid, dst_grid):
    assert(src_grid.shape == dst_grid.shape)
    mesh = []
    for i in range(src_grid.shape[0] - 1):
        for j in range(src_grid.shape[1] - 1):
            src_quad = [src_grid[i    , j    , 0], src_grid[i    , j    , 1],
                        src_grid[i + 1, j    , 0], src_grid[i + 1, j    , 1],
                        src_grid[i + 1, j + 1, 0], src_grid[i + 1, j + 1, 1],
                        src_grid[i    , j + 1, 0], src_grid[i    , j + 1, 1]]
            dst_quad = [dst_grid[i    , j    , 0], dst_grid[i    , j    , 1],
                        dst_grid[i + 1, j    , 0], dst_grid[i + 1, j    , 1],
                        dst_grid[i + 1, j + 1, 0], dst_grid[i + 1, j + 1, 1],
                        dst_grid[i    , j + 1, 0], dst_grid[i    , j + 1, 1]]
            dst_rect = quad_to_rect(dst_quad)
            mesh.append([dst_rect, src_quad])
    return mesh

im = Image.open('./old_driver/data/train/c0/img_292.jpg')
dst_grid = griddify(shape_to_rect(im.size), 4, 4)
src_grid = distort_grid(dst_grid, 50)
mesh = grid_to_mesh(src_grid, dst_grid)
im = im.transform(im.size, Image.MESH, mesh)
im.show()

Перед тем: enter image description here После: enter image description here

Я предлагаю выполнить указанный выше код в iPython, а затем распечатать mesh, чтобы понять, какой тип ввода необходим для im.transform. Для меня вывод:

In [1]: mesh
Out[1]:
[[(0, 0, 160, 120), [0, 29, 29, 102, 186, 120, 146, 0]],
 [(160, 0, 320, 120), [146, 0, 186, 120, 327, 127, 298, 48]],
 [(320, 0, 480, 120), [298, 48, 327, 127, 463, 77, 492, 26]],
 [(480, 0, 640, 120), [492, 26, 463, 77, 640, 80, 605, 0]],
 [(0, 120, 160, 240), [29, 102, 9, 241, 162, 245, 186, 120]],
 [(160, 120, 320, 240), [186, 120, 162, 245, 339, 214, 327, 127]],
 [(320, 120, 480, 240), [327, 127, 339, 214, 513, 284, 463, 77]],
 [(480, 120, 640, 240), [463, 77, 513, 284, 607, 194, 640, 80]],
 [(0, 240, 160, 360), [9, 241, 27, 364, 202, 365, 162, 245]],
 [(160, 240, 320, 360), [162, 245, 202, 365, 363, 315, 339, 214]],
 [(320, 240, 480, 360), [339, 214, 363, 315, 453, 373, 513, 284]],
 [(480, 240, 640, 360), [513, 284, 453, 373, 640, 319, 607, 194]],
 [(0, 360, 160, 480), [27, 364, 33, 478, 133, 480, 202, 365]],
 [(160, 360, 320, 480), [202, 365, 133, 480, 275, 480, 363, 315]],
 [(320, 360, 480, 480), [363, 315, 275, 480, 434, 469, 453, 373]],
 [(480, 360, 640, 480), [453, 373, 434, 469, 640, 462, 640, 319]]]
7 голосов
/ 22 февраля 2011

На аналогичной заметке вы можете использовать Python API ImageMagick для выполнения искажения Шепардса .

koala ears koala ears pull

5 голосов
/ 22 февраля 2011

Да, есть.Это немного низкоуровневый, но PIL (библиотека изображений Python) имеет функцию для такого рода преобразований.У меня никогда не было, чтобы это работало для меня (так как моя проблема была немного проще), но вы можете поиграть с этим.

Вот хороший ресурс для преобразований PIL (вы хотели бы взглянуть на MESH ): http://effbot.org/tag/PIL.Image.Image.transform.


Из документации:

Аналогично QUAD, но данные - этосписок целевых прямоугольников и соответствующих исходных четырехугольников.

im.transform(size, MESH, data)

Данные - это набор прямоугольников:

data = [((a, b, c, d), (e, f, g, h)), 
        ((i, j, k, l), (m, n, o, p))]

Преобразует первый прямоугольник во второй.

...