Skip to content

An interpreter of image transformations, inspired by *Beyond Photography: The Digital Darkroom*

License

Notifications You must be signed in to change notification settings

Pikecillo/darko

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

31 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Darko

Darko is an interpreter of image transformations inspired by Popi (Portable Pico), described in the classical book Beyond Photography: The Digital Darkroom by Gerard J. Holzmann.

Have fun distorting some pictures with one-liners, and feel free to contribute to this project.

Content

How to Run It

Darko is written in Python. To run it you need to install numpy and OpenCV. Last time it was tried with Python 3.7.6, but any Python 3 version should work.

$ pip install SimpleParse
$ pip install opencv-python

Run Demo

You can run a demo that generates all images shown in the Catalogue of Transformations by doing:

$ python darko.py

Run Darko Grammar Test

python -m pytest tests

A Tutorial

Let's apply some transformations on the following picture of scientist/physics-professor/safe-cracker/bongos-player/nobel-laureate extraordinaire Richard Feynman.

Feynman

Let's load the darko interpreter and an image, and let's operate on it using bilinear sampling

import darko.interpreter

# Create an interpreter
darko_interpreter = darko.interpreter.Interpreter()

# Load an image, and reads subpixels with bilinear interpolation
darko_interpreter.load('feynman.jpg', sampling='bilinear')

Not let's rotate the image by 45 degrees

# Apply the transformation
darko_interpreter.eval('new[x, y] = old[rect(r, a + rad(45))]')
# Save result to a file
darko_interpreter.save('feynman-rotated.jpg')

Feynman

Zooming-in on the image

darko_interpreter.eval('new[x, y] = old[rect(r / 2, a)]')
darko_interpreter.save('feynman-zoomed.jpg')

Feynman

Mirroring and translating the image

darko_interpreter.eval('new[x, y] = old[abs(X / 2 - x), y]')
darko_interpreter.save('feynman-mirrored.jpg')

Feynman

Thresholding the image in 2-pixel blocks

transformation = """
    new[x, y] = gray(old[floor(x / 2) * 2, floor(y / 2) * 2]) > 150 ?
	    rgb(255, 255, 255) : rgb(0, 0, 0)
"""
darko_interpreter.eval(transformation)
darko_interpreter.save('feynman-icon.jpg')

Feynman

A Warhol-like mosaic

transformation = """
    new[x, y] =
	        old[x % (X / 2) * 2, y % (Y / 2) * 2] *
                ((x < X / 2 ?
                 (y < Y / 2 ? rgb(255, 0, 0) : rgb(0, 255, 0)) :
                 (y < Y / 2 ? rgb(255, 255, 0) : rgb(0, 255, 255))) / Z)
"""
darko_interpreter.eval(transformation)
darko_interpreter.save('feynman-mosaic.jpg')

Feynman

A funky late 60s or early 70s look

transformation = """
    new[x, y] =
        0.33 * ((gray(Z - old[x - 25, y]) / Z) * rgb(0, 0, 255)) +
	        0.33 * ((gray(Z - old[x, y]) / Z) * rgb(0, 255, 0)) +
	        0.33 * ((gray(Z - old[x + 25, y]) / Z) * rgb(255, 0, 0))
"""
darko_interpreter.eval(transformation)
darko_interpreter.save('feynman-lsd.jpg')

Feynman

Keywords

You can use either polar coordinates or rectangular coordinates in your transformations. The origin of the rectangular coordinates is at the top-left corner of the image, and the origin of the polar coordinates is in the center of the image.

The following keywords can be used in transformations:

old: original image

new: transformed image

x: current pixel's x in rectangular coordinates

y: current pixel's y in rectangular coordinates

r: current pixel's radius in polar coordinates

a: current pixel's angle (in radians) in polar coordinates

cx: x of center of image rectangular coordinates

cy: y of center of image rectangular coordinates

R: Half-length of image diagonal

X: Width of image

Y: Height of image

Z: Depth of image (255)

Operators

The following operators can be used within expressions

Arithmetic: +, -, *, /, **, %

Comparison: <, >, ==, !=, <=, >=

Logic: &&, ||

Trinary: cond ? texpr : fexpr

Functions

rect(r, a) -> (x, y): Polar to rectangular coordinates

polar(x, y) -> (r, a): Rectangular to polar coordinates

sin(x): Sine

cos(x): Cosine

sqrt(x): Square root

deg(x): Radians to degrees

rad(x): Degrees to radians

gray(p): Gray level of pixel

rgb(r, g, b): Color tuple

ceil(x): Ceiling

floor(x): Floor

A Catalogue of Transformations

Most of the following transformations were taken from Beyond Photography: The Digital Darkroom.

Twist

new[x, y] = old[rect(r, a - r / 50)]

Putin Putin Twist

Bath

new[x, y] = old[x + (x % 32) - 16, y]

Merkel Merkel Bath

Wave

new[x, y] = old[x + 10 * sin(rad(y) * 10), y]

Obama Obama Wave

Funhouse

new[x, y] = old[x + sin(rad(x)) * 150, y + sin(rad(y * 1.18)) * 89]

Jinping Jinping Funhouse

Pond

new[x, y] = old[x, y + 10 * sin(rad(y) * 10)]

Cameron Cameron Pond

Negative

new[x, y] = Z - old[x, y]

Cook Cook Negative

Spiralbath

new[x, y] = old[x, y + (deg(a) + r / 4) % 64 - 16]

Gates Gates Spiralbath

Fisheye

new[x, y] = old[rect(1.5 * r ** 2 / R, a)]

Bezos Bezos

Caricature

new[x, y] = old[rect(0.5 * sqrt(r * R), a)]

Page Page Caricature

Curly

new[x, y] = old[x + 10 * sin(rad(y) * 5), y + 10 * sin(rad(x) * 5)]

Brin Brin Curly

Sink

new[x, y] = old[rect(r + 10 * sin(rad(r) * 10), a - r / 50)]

Ma Ma Sink

T2000

new[x, y] = old[rect(1.5 * r ** 2 / R + 10 * sin(rad(r) * 10), a)]

Zuckerberg Zuckerberg T2000

Pixel

new[x, y] = old[floor(x / 10) * 10, floor(y / 10) * 10]

Musk Musk

Bentley

new[x, y - gray(old[x, y]) * 0.1] = old[x, y]

Nadella Nadella Bentley

About

An interpreter of image transformations, inspired by *Beyond Photography: The Digital Darkroom*

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages