An Introduction to Pancito

[pronounced pan-see-toe]

Introduction

I can grab this project in both hands and try to stretch it into a nice, linear form with a beginning, middle and end, or I can tear it into a few more manageable chunks, each easier to describe than the whole. The second approach seems more interesting. So I'll describe the two ways I've used Pancito, first as a way of focussing on transformations, then as a way of mixing "natural" and "artificial" data. The final, third, chunk will look at the interface exposed to the user.

Functions as Images

In Pancito images are functions that return a colour for a particular point. A function that returned "blue" for all points would generate a uniform blue image, for example. The Pancito system makes it simple to connect functions together, producing progressively more complex images. The first non-trivial image I made, Red Square (right) repeatedly applies a function that "creases" an image, starting from a plain red square.

What makes Red Square so appealing is the organic nature of the final image, particularly when it has such a simple mathematical basis, although I didn't understand this at the time. I'll return to the topic of "naturalness" later, when I discuss images based on the transformation of photographs.

Soon after Red Square I began to explore how the same basic function could be repeated within a single image. I wanted to see first, how I could express the same function in different ways and second, if a recurring mathematical motif would give an image that was somehow internally self-consistent (much like a fractal, for example).

Hence the C Series. The basic function is shown by the displacement from a regular grid in Dots (C4) (left) - the displacement follows a "C", pushing left from bottom right, then up and round to top right.

I wasn't happy with the results. Dots C13 (right) was the most pleasing, but had no elegant, underlying mathematical structure: the colours were arbitrary and the structure composed of carefully selected subregions of earlier images. Maybe I wasn't sufficiently rigorous in applying and re-applying the function. More likely, following a rigid doctrine is not likely to produce good art.

Images as Functions

Two months ago I was under a lot of pressure at work. With little free time I turned to photograpy - in a free few minutes I could walk a couple of blocks from the office and snap a few pictures. A month later, with more free time (I resigned), I wondered about having some clothes printed with my favourite images.

However, CafePress don't print white. Images have to be printed onto light fabric which makes photos look clunky unless they have very light backgrounds. Or unless the image is processed to integrate a white background into the design.

So I extended Pancito. It's now possible to read an image (a photograph, for example) into the system. Once inside, it appears as a function - a function that just happens to return, at each position, the appropriate colour from the photo.

Street (left, larger) is a processed version of this photo. The transformation details (described by a bunch of functions) can be seen here. Text was added afterwards, using the gimp.

I was very happy with Street. It looked a little dated, maybe, a little formulaic, a little eighties, perhaps, but it also contained something interesting. The interest, I believe, comes from the natural variations (in this case in colour hue) taken from the photograph.

The next image, Squares (right, larger) tests this idea and works well. Based (pretty directly) on this photo, natural and synthetic interact on a number of scales (see, for example, this detail).

How far can this be taken? In this image the shifting and rotation of the bugs is calculated from another photo. I'm not sure it works; I had more success playing with the idea of pixels (detail).

Interface

Pancito is a library for the Haskell language. I don't want to describe that language here (if you're curious, follow these links). Instead, I'll give examples that give a little of the flavour of how it is used. My aim is to show that this isn't rocket science. If you can write basic programs, in whatever language, you can generate images with Pancito. More important than programming ability an intuitive feel for "maths" - Pancito lets you do maths with images (in a nice way!).

For example, to define a filter that gamma corrects an image (equally to all colours):

gamma-rgba :: Double -> Tint
gamma-rgba gamma colour = rgba ((r colour)**gamma) ((g colour)**gamma) 
                               ((b colour)*gamma) (a colour)

The first line is optional, as the compiler can work out what the function does, but it helps catch mistakes (if the function you describe isn't consistent with the description, then the compiler will complain). Instead of Tint, you could have written Colour -> Colour. If you wanted to work with hsv, and simply change the value (is don't think this is equivalent to the function above), you could write:

gamma-hsv :: Double -> Tint
gamma-hsv gamma colour = hsva (h colour) (s colour) ((v colour)**gamma) (a colour)

If you want to shift an image two pixels (assuming that's what the coordinates are) to the right:

right :: Transform
right = shift (-2.0) 0.0

And to put all this together, if you have an image im1, then the image shifted to the right and gamma-coorected to 1.5 is:

im2 :: Image
im2 = gamma 1.5 . im1 . right

Simple! (If you're curious, the "." is functional composition)

The important thing to remember is that images are functions. They take a position (Point) as an argument and return a Colour. That's why, in the description of im2 above, right appears to the right of im1 and gamma 1.5 appears to the left. When im2, itself a function, is applied to a point, the calculation of the appropriate colour flows from right to left - first the point is shifted (if you think carefully, this explains why it was shift (-2.0) 0.0 and not shift 2.0 0.0), then im1 converts the point to a coulour, then that colour is gamma corrected.

Of course, something as simple as this is also possible in any image processing package. The advantage of Pancito is that this all takes place inside a powerful (and very elegant) general purpose language. If you prefer to play around in Photoshop or Gimp, then I'm not suggesting that you change. But if you are frustrated with doing repetitive, interactive tasks, consider automating them with Pancito (I use the Gimp to prepare images for processing by Pancito and to add text, do scaling, etc. afterwards).

Finally, a word on Pancito's limitations. The major limitation comes from the functional approach that transforms points to colours. When an image of a function is generated, that image is sampled (at the centre of each pixel in the simplest case; things are more complicated when anti-aliasing is used). A naive implementation of a line (something like if y - x^2 = 4.0 then black else white will not be displayed because it is "infinitely thin". The chance of any pixel lying on the line is vanishingly small. Of course, you can use something like:

curve :: Image
curve p = if line then black else white
  where
    (x', y') = (x p, y p)
    z = y' - x'^2
    line = z > 3.5 && z < 4.5

But what line thickness will this generate? And will that line thickness remain the same when coordinates are transformed? A little thought suggest that this approach could be made to work in a limited case (splines, for example?) with more analysis.

The second, more minor, limitation is that Pancito probably isn't as fast as a dedicated language for image processing. For example, generating images for cafepress t-shirts (4000x3200 pixels, anti-aliased, no longer available) can take several hours. But I don't generate images at this resolution when I am developing an idea. At lower resolutions (400x320, with no aliasing) there is no problem (I generally use a coordinate system that is independent of the number of pixels, so changing from 400x320 to 4000x3200 implies changing just one or two numbers in the script).

Conclusion

I hope that this short essay has helped you understand the strengths and weaknesses of Pancito. Please mail me if you have any questions, but note that I have not used this package (or Haskell) for years. Have fun.