Увеличить изображение до уровня пикселей - PullRequest
3 голосов
/ 06 апреля 2010

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

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

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

Увеличение изображения на GitHub

Ответы [ 3 ]

5 голосов
/ 07 апреля 2010

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

image[x][y]

Тогда значения цвета увеличенного изображения равны

image[x+zf*(px-x)][y+zf*(py-y)]

Относительно размера окон / размера изображения - первоначальная подготовка изображения должна позаботиться об этом: увеличьте изображение до такой степени, что оно больше не будет соответствовать окну, и заполните оставшиеся пиксели предпочитаемым цветом фона.

В Python вы можете сделать что-то вроде

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 вы получите

альтернативный текст http://i40.tinypic.com/i1cwg7.jpg

для zf = 0,3, вокруг точки 25,6

альтернативный текст http://i41.tinypic.com/24g5848.png

для zf = 0,96, примерно в той же точке

Изображения получены с использованием следующего кода

#!/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()

Используемые библиотеки и попиксельный подход не самые быстрые в мире, но предоставят вам достаточно материала для игры.

Также приведенный выше код не очень чистый.

EDIT2 (and3, центрированная формула): Вот еще одна попытка, добавлен перевод, но я чувствую, что это не окончательный вариант (у меня нет времени, чтобы проверить формулы). Также скорость перевода постоянна, но это может привести к медленному масштабированию и отображению фона (если точка, к которой вы масштабируете, находится слишком близко к краю).
Я также добавил точку на исходное изображение, чтобы было видно, что с ним происходит, без необходимости рисовать исходное изображение.

#!/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 голосов
/ 06 апреля 2010

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

0 голосов
/ 06 апреля 2010

Редактировать : Для арт-проектов вы можете проверить эту структуру: Обработка

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

Если вы хотите линейное преобразование, оно имеет вид:

D (x) = ax + b

Вы хотите:

для z = 0: D (px) = px D (px + 1) = px + 1

для z = 1: D (px) = 0 D (px + 1) = sw

Это дает:

для z = 0: a = 1, b = 0, D (x) = x

для z = 1: a = sw, b = -sw.px, D (x) = sw.x - sw.px

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

D (x) = z (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 - z)

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...