Манипуляция пикселями изображения напрямую
Был вдохновлён данным видео https://www.youtube.com/watch?v=gLzuTcyjRVI про конформные отображения. Я пробовал реализовать подобное через python. В качестве конформного отображения для начала выбирал функцию линейную.
import numpy as np
import matplotlib.pylab as plt
# def func_zhukovsky(z):
# return (z + 1 / z) / 2
def func_linear(z, k, b):
return z * k + b
img = plt.imread('./img.jpg')
res = img.copy()
for y in range(1620):
for x in range(2160):
z = complex(x, y)
Z = func_linear(z, 1, -300)
if 0 < Z.real < 1620 and 0 < Z.imag < 2160:
res[int(Z.real), int(Z.imag)] = res[x, y]
else:
res[x, y] = 0
plt.imshow(res)
plt.show()
Хоть и получил линейный сдвиг на 300px (как и ожидалось), есть чувство как будто всё делаю не так.
- Во-первых, проход по изображению выходит слегка долгим (возможно, так и должно быть. я не знаю). Может мне стоило использовать модуль Pillow
- Во-вторых, меня сейчас больше волнует, как на видео удалось добиться плавного отображения одной области в другую. Это просто использовали кучу фото подряд?
- В-третьих, вот эта строчка
res[int(Z.real), int(Z.imag)] = res[x, y], наверняка, сильно огрубляет результат (если бы использовал в качестве отображения не линейную функцию, а функцию Жуковского, то вряд ли бы получил то, что хотел). Слышал, что в JavaScript пиксели могут принимать дробные значения. Может стоило вообще на JS писать?
Поэтому мой главный вопрос такой: какое средство мне выбрать, чтобы реализовать что-то подобное, как на видео? Спасибо
Вот кстати результат программы, кому интересно:
Ответы (1 шт):
Если поместить ваши циклы внутрь функции и обернуть потом эту функцию и func_linear в декоратор jit из пакета numba, то всё будет летать без дополнительных усилий. При первом вызове функция немного притормозит, поскольку ей надо будет скомпилироваться (но всё равно выполнится быстрее), а последующие вызовы будут по меньшей мере в 10 раз быстрее работать, а то и в 100.
Картинки вашей у меня нет, поэтому использую произвольный numpy массив.
import numpy as np
import matplotlib.pylab as plt
from numba import jit
# def func_zhukovsky(z):
# return (z + 1 / z) / 2
@jit
def func_linear(z, k, b):
return z * k + b
img = np.ones((2160,1620))
res = img.copy()
@jit
def doit(res):
for y in range(1620):
for x in range(2160):
z = complex(x, y)
Z = func_linear(z, 1, -300)
if 0 < Z.real < 1620 and 0 < Z.imag < 2160:
res[int(Z.real), int(Z.imag)] = res[x, y]
else:
res[x, y] = 0
Без декоратора: 3 секунды
С декоратором: 300 мс, при повторных вызовах функции возможно ещё быстрее будет - в первый вызов numba ещё и успевает скомпилировать функции.
