Если цветовые значения исходного изображения приведены в виде массива
image[x][y]
Затем цвет значение увеличенного изображения является
image[x+zf*(px-x)][y+zf*(py-y)]
Что касается окон размера/размера изображения - начальная подготовки изображения должны заботиться из этого: увеличьте изображение до такой степени, чтобы оно больше не соответствовало окну и заполнило оставшиеся пиксели предпочтительным цветом фона.
В питона вы можете сделать что-то вроде
def naivezoom(im, px, py, zf, bg):
out = Image.new(im.mode, im.size)
pix = out.load()
iw, ih = im.size
for x in range(iw):
for y in range(ih):
xorg = x + zf*(px - x)
yorg = y + zf*(py - y)
if xorg >= 0 and xorg < iw and yorg >= 0 and yorg < ih:
pix[x,y] = im.getpixel((xorg , yorg))
else:
pix[x,y] = bg
return out
после установки
im = Image.open("filename.ext")
с объектами из
import Image
EDIT: Учитывая StackOverflow логотип вы получите
alt text http://i40.tinypic.com/i1cwg7.jpg
для ZF = 0,3, вокруг точки 25,6
alt text http://i41.tinypic.com/24g5848.png
для = 0,96 ZF, примерно в то же точке
Изображения были получены со следующим кодом
#!/bin/env python
from Tkinter import *
import Image
import ImageTk
def naivezoom(im, p, zf, bg):
out = Image.new(im.mode, im.size)
pix = out.load()
iw, ih = im.size
for x in range(iw):
for y in range(ih):
xorg = x + zf*(p[0] - x)
yorg = y + zf*(p[1] - y)
if xorg >= 0 and xorg < iw and yorg >= 0 and yorg < ih:
pix[x,y] = im.getpixel((xorg , yorg))
else:
pix[x,y] = bg
return out
class NaiveTkZoom:
def __init__(self, parent=None):
root = Tk()
self.im = Image.open('logo.jpg')
self.zf = 0.0
self.deltazf = 0.02
self.p = (0.1*self.im.size[0],0.1*self.im.size[1])
self.bg = 255
canvas = Canvas(root, width=self.im.size[0]+20 , height=self.im.size[1]+20)
canvas.pack()
root.bind('<Key>', self.onKey)
self.canvas = canvas
self.photo = ImageTk.PhotoImage(self.im)
self.item = self.canvas.create_image(10, 10, anchor=NW, image=self.photo)
def onKey(self, event):
if event.char == "+":
if self.zf < 1:
self.zf += self.deltazf
elif event.char == "-":
if self.zf > 0:
self.zf -= self.deltazf
self.out = naivezoom(self.im, self.p, self.zf, self.bg)
self.photo = ImageTk.PhotoImage(self.out)
self.canvas.delete(self.item)
self.item = self.canvas.create_image(10, 10, anchor=NW, image=self.photo)
print self.p, self.zf
if __name__ == "__main__":
NaiveTkZoom()
mainloop()
Используемые библиотеки и пиксельный подход не являются самыми быстрыми в мире, b ut даст вам достаточно материала для игры.
Также приведенный выше код не очень чист.
EDIT2 (и3, с центрированной формулой): Вот еще одна попытка, добавленный перевод, но у меня такое чувство, что это тоже не окончательно (у меня нет времени проверять формулы). Также скорость перевода постоянна, но это может привести к уменьшению масштаба и отображению фона (если точка, к которой вы увеличиваете масштаб, слишком близко к краю).
Я также добавил точку на исходном изображении, чтобы было видно, что с ней происходит, без необходимости рисовать на исходном изображении.
#!/bin/env python
from Tkinter import *
import Image
import ImageTk
def markImage(im, p, bg):
pix = im.load()
pix[ p[0], p[1] ] = bg
def naiveZoom(im, p, zf, bg):
out = Image.new(im.mode, im.size)
pix = out.load()
iw, ih = im.size
for x in range(iw):
for y in range(ih):
xorg = x + zf*(p[0]+0.5-x) + zf*(1-zf)*(p[0]-iw/2)
yorg = y + zf*(p[1]+0.5-y) + zf*(1-zf)*(p[1]-ih/2)
if xorg >= 0 and xorg < iw and yorg >= 0 and yorg < ih:
pix[x,y] = im.getpixel((xorg , yorg))
else:
pix[x,y] = bg
return out
class NaiveTkZoom:
def __init__(self, parent=None):
root = Tk()
self.im = Image.open('py.jpg')
self.zf = 0.0
self.deltazf = 0.05
self.p = (round(0.3*self.im.size[0]), round(0.3*self.im.size[1]))
self.bg = 255
markImage(self.im, self.p, self.bg)
canvas = Canvas(root, width=self.im.size[0]+20 , height=self.im.size[1]+20)
canvas.pack()
root.bind('<Key>', self.onKey)
self.canvas = canvas
self.photo = ImageTk.PhotoImage(self.im)
self.item = self.canvas.create_image(10, 10, anchor=NW, image=self.photo)
self.change = False
def onKey(self, event):
if event.char == "+":
if self.zf < 1:
self.zf += self.deltazf
self.change = True
elif event.char == "-":
if self.zf > 0:
self.zf -= self.deltazf
self.change = True
if self.change:
self.out = naiveZoom(self.im, self.p, self.zf, self.bg)
self.photo = ImageTk.PhotoImage(self.out)
self.canvas.delete(self.item)
self.change = False
self.item = self.canvas.create_image(10, 10, anchor=NW, image=self.photo)
print self.p, self.zf
if __name__ == "__main__":
NaiveTkZoom()
mainloop()
В вышеуказанном состоянии достаточно много улучшений. :)
Не могли бы вы сначала уточнить, хотите ли вы только финальное изображение или анимацию с помощью серии уровней масштабирования? Если вам нужна анимация, вам нужно будет не только описать уровни максимального и минимального масштабирования (0 и 1), но и скорость, при которой камера движется линейно или нет (линейная немного неестественна, она мгновенно ускоряется и останавливается). Кроме того, поскольку пиксель, на который выполняется масштабирование камеры, в общем случае не в центре, происходит не только масштабирование, но и перевод камеры, чтобы получить пиксель; это можно было бы считать линейным, но подтверждение было бы хорошим. – Unreason
Также примечание - алгоритм будет прост, но я бы скорее назвал использование существующих библиотек более умным. – Unreason
Для данного коэффициента масштабирования я просто хочу создать единый кадр изображения. Впоследствии я сделаю шаг с коэффициентом масштабирования от 0 до 1, чтобы создать анимацию. Скорость определения сложнее определить - я ищу «естественное» движение к пикселю, когда вы переходите от 0 до 1 коэффициента масштабирования с фиксированным шагом (его не нужно фиксировать, но это было бы замечательно). Также я не возражаю против использования существующих библиотек. – zaf