2010-04-06 3 views
3

Для арт-проекта одна из вещей, которые я буду делать, - это масштабирование изображения на определенный пиксель. Я протирал себе подбородок и хотел бы посоветовать, как действовать дальше.Увеличить изображение на уровень пикселей

Вот входные параметры:

Screen: 
sw - screen width 
sh - screen height 

Image: 
iw - image width 
ih - image height 

Pixel: 
px - x position of pixel in image 
py - y position of pixel in image 

Zoom: 
zf - zoom factor (0.0 to 1.0) 

Background colour: 
bc - background colour to use when screen and image aspect ratios are different 

Выходы:

The zoomed image (no anti-aliasing) 
The screen position/dimensions of the pixel we are zooming to. 

When zf is 0 the image must fit the screen with correct aspect ratio. 
When zf is 1 the selected pixel fits the screen with correct aspect ratio. 

Одна идея у меня было использовать что-то вроде Povray и приближать камеру к большой текстуры изображения или какой-либо библиотеки (например, pygame), чтобы сделать масштабирование. Кто-нибудь думает о чем-то более умном с простым псевдокодом?

Чтобы сделать его более простым, вы можете сделать изображение и экран одинакового соотношения сторон. Я могу жить с этим.

Я обновлю дополнительную информацию по мере необходимости.

UPDATE

Старинное общепринятый ответ на PHP

Image Pixel Zoom on GitHub

+0

Не могли бы вы сначала уточнить, хотите ли вы только финальное изображение или анимацию с помощью серии уровней масштабирования? Если вам нужна анимация, вам нужно будет не только описать уровни максимального и минимального масштабирования (0 и 1), но и скорость, при которой камера движется линейно или нет (линейная немного неестественна, она мгновенно ускоряется и останавливается). Кроме того, поскольку пиксель, на который выполняется масштабирование камеры, в общем случае не в центре, происходит не только масштабирование, но и перевод камеры, чтобы получить пиксель; это можно было бы считать линейным, но подтверждение было бы хорошим. – Unreason

+0

Также примечание - алгоритм будет прост, но я бы скорее назвал использование существующих библиотек более умным. – Unreason

+0

Для данного коэффициента масштабирования я просто хочу создать единый кадр изображения. Впоследствии я сделаю шаг с коэффициентом масштабирования от 0 до 1, чтобы создать анимацию. Скорость определения сложнее определить - я ищу «естественное» движение к пикселю, когда вы переходите от 0 до 1 коэффициента масштабирования с фиксированным шагом (его не нужно фиксировать, но это было бы замечательно). Также я не возражаю против использования существующих библиотек. – zaf

ответ

4

Если цветовые значения исходного изображения приведены в виде массива

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

Ницца! Спасибо за уравнение и образец кода. Одна вещь, которую я заметил, это то, что если, скажем, выбранный пиксель находится где-то в верхнем левом квадранте, тогда он обнимает верхний левый угол при увеличении. Вместо этого, когда вы увеличиваете масштаб, я ищу выбранный пиксель, чтобы центрировать себя , – zaf

+0

Обновлен ответ, не обнимая здесь, вы уверены, что правильно применяете приведенные формулы? – Unreason

+0

Спасибо за обновленный код. Мне очень нравились клавиши +/-! OK - попробуйте изображение с красным (или любым цветовым маркером) на изображении, а затем увеличьте его, и вы увидите, что левая верхняя часть выбранного пикселя остается на месте. Нам нужен пиксельный центр на экране. Я использую изображение 1000x1000 с красным пикселом в 300 300. – zaf

0

Редактировать: Для художественных проектов, которые вы можете проверить эту схему: Processing

я делаю это для 1D, вы начинаете написав прямое преобразование от исходного изображения к увеличенному изображению с ограничениями:

Как вы хотите, линейное преобразование, то в виде:

D (х) = ах + Ь

Вы хотите :

при г = 0: D (ПВ) = рх D (рх + 1) = рх + 1

при г = 1: D (ПВ) = 0 D (рх + 1) = s ж

Это дает:

при г = 0: а = 1, B = 0, Д (х) = х

при г = 1: а = Sw, B = -sw. ПВ, D (х) = sw.x - sw.px

Для всех г, можно использовать линейную комбинацию двух:

D (х) = г (sw.x - sw.px) + (1 - z) (x) D (x) = (z.sw + 1 - z) .x - z.sw.px

Теперь вы записываете обратную функцию для получения исходных координат с выхода координаты:

ID (XOUT) = (XOUT + z.sw.px)/(z.sw + 1 - г)

Который позволяет заполнить выходного изображения из входное изображение.Для каждого выходного пикселя это значение OriginalPixel [ID (xout)] (И если ID (xout) не находится в [0..sw], вы используете фоновое значение)

Для 2D идея аналогична, но сохраняется соотношение сторон потребует немного больше усилий.

+0

Интересная мысль о 1D. Я постараюсь понять ваши уравнения и посмотреть, смогу ли я окунуться в них. Да, я играл с обработкой, очень крутой, возможно, первым инструментом, который я использую, если не могу сделать это вручную. – zaf

0

Если я правильно понимаю, что вы хотите делать. Вы можете открыть изображение в графической программе (например, Gimp), установить уровень масштабирования в 1 и сделать снимок экрана. Затем увеличьте уровень масштабирования и снимите снимок экрана и т. Д. Затем используйте mencoder для создания AVI со скриншотов.

+0

Возможно, вы также можете написать сценарий для запуска imagemagic с инкрементными уровнями шкалы и фиксированным вытиранием. Сохраните каждое масштабированное изображение с такими именами, как 001.jpg 002.jpg ... и используйте mencoder для создания разных фильмов. – Ross

+0

Если я не возьмусь за уравнения, тогда я изучу автоматизацию других инструментов, но я знаю, что мне придется попробовать новые инструменты, прежде чем найти тот, который дает мне эффект, который я ищу. – zaf