Archive of articles classified as' "graphics"

Back home

Using stochastic processes to generate paint type effects in processing.org

15/06/2010
I very much like to play with processing.org when I’ve got some downtime. I’ve wrote a small particle engine a while back in the framework and this time I thought I’d try and do something a little more arty from the outset. My inspiration for this “sketch” was the many splatter paintings by Jackson Pollock. I can remember going to see some of his work at the Tate modern in London quite a long time ago. I had always thought it a bit poor as “art” when I was a kid but later on I developed an appreciation for the format. If you have no idea what I’m talking about, this is an example:
Now my sketches don’t look much like this but I did capture some of that splattering chaotic effect that I wanted. The basic process is very simple, a class called a Walker will randomly make its way across the canvas. As it moves the vector distance of each step is calculated. If the step is big enough it causes a burst of circles to be drawn, each with a slightly random position & varied alpha to give it some texture. To avoid it becoming a little too busy I’ve limited it to a set palette at runtime which can be regenerated as walkers are added.

I was quite happy with the random scatter effect as different pools of colour made their way through the canvas space. I thought it would be a nice addition to add in some basic boundary conditions so I added a quick polygon class and added in an array of those. A few functions later and I could click around the screen defining new polygons. Using the well known Jordan Curve theorem we can tell if the walker is currently within an arbitrary polygon (without holes of course). Here’s an example video of it in action. Heart’s seem pretty easy to draw compared to anything crazy complex and give a good idea of the effect:

I’ve added quite a few options to the code now allowing me to switch on & off the boundaries as well as add an arbitrary number of polygons. If the vertices overlap then the way the “point in polygon” algorithm works it will flag each “contained” area as a solid.
Finally here is a nicely captured heart shape. It gives a nice idea of the kind of effect when combined with a boundary. I think playing around with the way the walkers are coded could be fun, for example doing a neighbour check and tweaking the randomised movement accordingly could create a weak flocking style system with Brownian motion driving it.
If you’re interested in checking the code out you can find it over on github. It should run for you ok out of the box within your processing environment.
No Comments

Building CSS sprites with Bash & Imagemagick

3/05/2010

I’ve been rebuilding the Crooked Tongues forum and one of the things we’ve been mindful of is trying to stick to some good practises with regards optimzing the site for fast loading. One of the easy ways to decrease your page load times is to use CSS sprites. This is just stiching together all your common images into one big one and then using background positions & width/heights in CSS to offset and “crop” the big image. This way you only get the one HTTP request made to request it.

If you’ve got hundreds of small images it can really speed up your page. A prime candidate for sprites are typically your buttons, header images and in the case of a forum, emoticons. Crooked uses lots of custom designed icons and when writing them out as individual images for the post toolbar really slowed down the page. There was no chance I was going to do it manually so I turned to a stable of my web development toolset – Imagemagicks convert.

Convert can do a lot. I’ll show you two such ways it made my life easier and cut down on the time I had to spend doing grunt work. First, here’s how the toolbar looks:

I wrote some bash to basically loop over a folder of images and then using convert to pull the width & height info, I use that to write the CSS file. Finally I loop over the images once more using the append command to output one big, long image. (gist)

#!/bin/bash
 
# uses imagemagick to stich together all images in a folder and
# then writes a css file with the correct offsets along with a
# test html page for verification that its all good
 
if [ $# -gt 0 ]
then
 
    if [ $3 ]
    then
        ext="."$3; # the extension to iterate over for input files
    else
        ext=".gif"; # the extension to iterate over for input files
    fi
 
    name=$1; # output will be placed in a folder named this
 
    if [ $2 ]
    then
        classname=$2"-sprite";
    else
        classname=$1"-sprite";
    fi
    css="$name/$classname.css";
    html="$name/test.html";
 
    rm -fr $name;
    mkdir $name;
    touch $css $html;
 
    echo "Generating sprite file...";
    convert *$ext -append $name/$classname$ext;
    echo "Sprite complete! - Creating css & test output...";
 
    echo -e "<html>\n<head>\n\t<link rel=\"stylesheet\" href=\"`basename $css`\" />\n</head>\n<body>\n\t<h1>Sprite test page</h1>\n" >> $html
 
    echo -e ".$classname {\n\tbackground:url('$classname$ext') no-repeat top left; display:inline-block;\n}" >> $css;
    counter=0;
    offset=0;
    for file in *$ext
    do
        width=`identify -format "%[fx:w]" "$file"`;
        height=`identify -format "%[fx:h]" "$file"`;
        idname=`basename "$file" $ext`;
        clean=${idname// /-}
        echo ".$classname#$clean {" >> $css;
        echo -e "\tbackground-position:0 -${offset}px;" >> $css;
        echo -e "\twidth: ${width}px;" >> $css;
        echo -e "\theight: ${height}px;\n}" >> $css;
 
        echo -e "<a href=\"#\" class=\"$classname\" id=\"$clean\"></a>\n" >> $html;
 
        let offset+=$height;
        let counter+=1;
        echo -e "\t#$counter done";
    done
 
    echo -e "<h2>Full sprite:</h2>\n<img src=\"$classname$ext\" />" >> $html;
    echo -e "</body>\n</html>" >> $html;
 
    echo -e "\nComplete! - $counter sprites created, css written & test page output. ~jaymz";
 
else
 
    echo -e "There should be at least 1 argument!\n\tbuildSprite.sh output_folder classname input_extension"
 
fi

The script outputs the names incrementing by one, I’ve gone over myself and turned them into “nice” names. All in all its taken maybe 10 minutes to convert it all into a sprite and nice CSS file. If you were using a primary key field like 1, 2, 3… etc then you could probably fudge it to not even have to name the id’s “nicely”.

Imagemagicks convert can also do some modification of your files. It can for example convert your image to a black & white copy. It’s not a great deal of work to then loop over a set of images, create b&w versions in a temporary folder and then stitch the two versions together to get a color→b/w sprite for hovers. I’ve actually seen people do this manually and spend an age at it, with this method you output them once then sit back for the 30 seconds or so whilst the computer does the work.

for file in *.jpg; do convert -colorspace Gray $file bw/$file; done
for file in *.jpg; do convert $file bw/$file -append sprites/$file; done

It’s times like this that I am reminded of just how much time you can save with a little shell script and the right command line tools. Not everthing needs point & click.

1 Comment

Image color analysis for your ecom site

22/04/2010

Recently we’ve been working rather hard on a new look and complete re-launch of the underlying code for the whole of crookedtongues.com We’re a python shop these days so its running on django with a host of apps and the best part of over 100,000 lines of code.

One of the things that I was tasked with was the data migration and import and I’ll write about that post launch, what I fancy getting out now is how I’ve worked on adding color codes automagically to the store’s entire product database. More or less, its a little rough round the edges but gives fairly good results on a lot of our products. First off you can find the source code in a raw (read that as ‘I’m still working on it personally so take it as it comes’) way over at github. As a taste of what it does, here’s a couple of existing product shots:

It works quite well for colors that fall into the center areas of the color wheel. For my analysis I’ve segmented it by 30° so there are 12 bands of color. I’ve found that yellow & light greens are the most tricky to pull out accurately from an instinctive perception view of the result. By that I mean what looks very much yellow can get labelled as a bright orange instead as values close to the segment boundary (45°) cause an imbalance towards the orange side.

The basic process is working well for products with one dominating color, for multi-color shots it can pull out the relative levels of each tones hue band but blindly chooses the largest, however slight and uses that for its naming output. A better way would be to do some further analysis on the collected results for each image – one way to enforce some confidence that the main hue really is the main color would be to compare its standard deviation from the average across the sample set. A small σ would indicate a more uniform mix of colors – as we have already sampled out low saturation points this would indicate an image of strong multicolor. Taking the set of hue/tones within the 90th percentile and then comparing their relative deviations of count would allow identifying (and quantifying) the number of colors – so it would be possible to say mainly dark blue with a little light red.

If two bands had similar counts it is also more likley that the color in question is not two separate closely aligned colors but in fact a single color at the midpoint (or thereabouts) of them. A scheme to compare these before the final decision would no doubt improve the detection of yellow which seems to constantly tip into the orange side of the wheel. All in all working on this has been a decidedly pleasant break from data imports, javascript and enough MVC style code to do me a lifetime.

Since I wrote the above I’ve tweaked it somewhat to pull out gray (and black/white) counts also. It works out the rough percentage that corresponds to and if its over a certain limit for black or white will output a value for that also (with a lot of the product shots they’re on a white background so I need to be more granular with that than just regular colors).

#!/usr/bin/python
# -*- coding: utf-8 -*-
 
# A color analysis script to help you label your store's products with color data
# automagically. It will take either a single file or scour an entire folder for
# folders of images and do each one individually printing a summary of what it
# thinks is the correct color value. A work in progress...
#
# ~jaymz | @jaymzcampbell | jaymz.eu
#
#
# MIT Licesnsed for what its worth, copy: http://www.opensource.org/licenses/mit-license.php
 
import Image
import ImageFilter
import os
import glob
import sys
import colorsys
import re
from copy import copy
from operator import itemgetter
from decimal import Decimal
 
output = open('colors.csv', 'w')
 
# Pixels will be first compared to these values before being
# added to the data list of color information on the first pass
LBOUND = 0
UBOUND = 255
 
MIN_SATURATION = 30 # avoid washed out pixels influencing counts
 
# Base folder for the processFolder function, it'll iterate over here on subfolders
FOLDER = '/home/jaymz/documents/crooked-docs/data-export/store-migration/product-images/'
 
# Meh, i need to flip between these two, you can probably tweak this 
SUMMARY_FORMAT, SQL_FORMAT = True, True
 
# Names based off: http://bluelobsterart.com/wordpress/wp-content/uploads/2009/03/rgb-color-wheel-lg.jpg
COLOR = ['RED', 'ORANGE', 'YELLOW',
    'LIME', 'GREEN', 'TURQUOISE',
    'CYAN', 'OCEAN', 'BLUE',
    'VIOLET', 'MAGENTA', 'RASPBERRY',
    ]
TONE = ['DARK', '', 'BRIGHT']
 
# via the createColorSQL.py file , addition added in GRAY/BLACK/WHITE to after this
SQL_IDS = {'DARK YELLOW': 7, 'DARK ORANGE': 4, 'BRIGHT GREEN': 15, 'BRIGHT ORANGE': 6, 'DARK RED': 1, 'BRIGHT OCEAN': 24, 'BRIGHT RED': 3, 'DARK OCEAN': 22, 'YELLOW': 8, 'OCEAN': 23, 'BRIGHT YELLOW': 9, 'RASPBERRY': 35, 'GREEN': 14, 'BRIGHT TURQUOISE': 18, 'CYAN': 20, 'MAGENTA': 32, 'RED': 2, 'ORANGE': 5, 'BLUE': 26, 'TURQUOISE': 17, 'LIME': 11, 'BRIGHT LIME': 12, 'DARK MAGENTA': 31, 'DARK LIME': 10, 'BRIGHT MAGENTA': 33, 'BRIGHT VIOLET': 30, 'DARK VIOLET': 28, 'DARK BLUE': 25, 'BRIGHT BLUE': 27, 'VIOLET': 29, 'BRIGHT RASPBERRY': 36, 'DARK TURQUOISE': 16, 'DARK CYAN': 19, 'BRIGHT CYAN': 21, 'DARK GREEN': 13, 'DARK RASPBERRY': 34}
 
pcnt = 0
 
def trimFloat(val, places=2):
    return float(repr(val)[0:places+2])
 
def withinBounds(allowance, _rgb):
    rgb = copy(_rgb)
    diff = 0
    allowance = Decimal(repr(allowance))
    for c in rgb:
        for d in rgb:
            dec_d = Decimal(repr(d)).quantize(allowance)
            dec_c = Decimal(repr(c)).quantize(allowance)
 
            diff = abs(dec_d-dec_c)
 
            if (d != c) and diff>allowance:
                return False
    return True
 
def processImage(i, name=None):
  """ Scales down the image, blurs it to ease the blending of the color values
and reduce spikes from anomolies. It then samples pixels creating a list of
colors. This list is then looped over to build counts which are placed into
bins of 30° hue's seperated into three based on their value. Pixels less than
a certain saturation are discarded. """
 
  global pcnt
 
  i = i.resize((200,200))
  i = i.convert("RGB")
  i = i.filter(ImageFilter.BLUR)
  d = i.getdata()
  cnt = 0
 
  h = [] #holds the hsv info
  grays = [] #holds just gray content
  black_count = 0
  white_count = 0
  total_samples = 0
 
  for p in d:
      cnt = cnt + 1
      if cnt == 8: #take every 4th pixel
        if p[0]>LBOUND and p[1]>LBOUND and p[2]>LBOUND and p[0]<UBOUND and p[1]<UBOUND and p[2]<UBOUND:
            r = trimFloat(float(p[0])/255)
            g = trimFloat(float(p[1])/255)
            b = trimFloat(float(p[2])/255)
 
            if not withinBounds(0.02, (r,g,b)):
                h.append(colorsys.rgb_to_hsv(r,g,b))
            else:
                if (r+g+b)/3>0.94:
                    white_count += 1
                elif (r+g+b)/3<0.3:
                    black_count += 1
                else:
                    grays.append(colorsys.rgb_to_hsv(r,g,b))
            total_samples += 1
        cnt = 0 #reset sample counter
 
  h.sort()
  grays.sort()
  bin_width = 30 # size of hue slices (degress)
  max_bin = 360
 
  darks = [0] * int(max_bin/bin_width)
  mids = [0] * int(max_bin/bin_width)
  lites = [0] * int(max_bin/bin_width)
 
  for p in h[::]:
      hue = p[0]*360
      sat = p[1]*100
      val = p[2]*100
      if sat >= MIN_SATURATION:
        bin_number = ((int(hue)+15)/bin_width)%(max_bin/bin_width)
        if val<33:
            darks[bin_number] += 1
        elif val>33 and val < 66:
            mids[bin_number] += 1
        else:
            lites[bin_number] += 1
        #print "HUE BIN: %s VALUE : %d" % (int(hue)/bin_width, int(hue))
 
  c = 0
  data = zip(darks, mids, lites)
 
  if SUMMARY_FORMAT:
    for x in data:
        print '%d %s : %s %d°' % (c, COLOR[c], x, c*bin_width)
        c += 1
 
  # the following area needs a rework. the index technique works alright as long
  # as counts and values dont all match up, then it starts picking the first one
  # so this needs re-writing to better order the list data
 
  darks_sort, mids_sort, lites_sort = darks[::], mids[::], lites[::]
  darks_sort.sort()
  mids_sort.sort()
  lites_sort.sort()
 
  sorted_counts = (darks_sort, mids_sort, lites_sort)
 
  primary_idx = (darks.index(sorted_counts[0][-1]), mids.index(sorted_counts[1][-1]), lites.index(sorted_counts[2][-1]))
  primary_cnts = (darks[primary_idx[0]], mids[primary_idx[1]], lites[primary_idx[2]])
  tone = primary_cnts.index(max(primary_cnts))
  max_hbin = primary_idx[tone]
 
  pcnt += 1
 
  if SUMMARY_FORMAT:
    print "\nDominant Hue: %s %s" % (TONE[tone], COLOR[max_hbin])
 
  if SQL_FORMAT and name and max(primary_cnts) > 30:
    output.write('%d, %s, %s\n' % (pcnt, name, SQL_IDS[' '.join([TONE[tone], COLOR[max_hbin]]).strip()]))
 
  sorted_counts[0][-1], sorted_counts[1][-1], sorted_counts[2][-1] = (0, 0, 0) # kind of reset the primary to null
  for l in sorted_counts:
      l.sort()
 
  primary_idx = (darks.index(sorted_counts[0][-1]), mids.index(sorted_counts[1][-1]), lites.index(sorted_counts[2][-1]))
  primary_cnts = (darks[primary_idx[0]], mids[primary_idx[1]], lites[primary_idx[2]])
  tone = primary_cnts.index(max(primary_cnts))
  max_hbin = primary_idx[tone]
 
  if SUMMARY_FORMAT:
    print "Secondary Hue: %s %s" % (TONE[tone], COLOR[max_hbin])
 
  if SQL_FORMAT and name and max(primary_cnts) > 30:
    pcnt += 1
    output.write('%d, %s, %s\n' % (pcnt, name, SQL_IDS[' '.join([TONE[tone], COLOR[max_hbin]]).strip()]))
 
  # area to rewrite ends...
 
  gray_total = [(g[0]+g[1]+g[2])/3 for g in grays]
  gray_average = reduce(lambda x,y : x+y, gray_total)/len(gray_total)
 
  black_percent = black_count/float(total_samples)*100
  gray_percent = len(gray_total)/float(total_samples)*100
  white_percent = white_count/float(total_samples)*100
 
  if SUMMARY_FORMAT:
    print "\nAverage Gray: %s (samples: %0.1f%%), White count: %s (%0.1f%%), Black count: %s (%0.1f%%)" % (gray_average, gray_percent, white_count, white_percent, black_count, black_percent)
    print "Total samples taken: %s\n\n" % total_samples
 
  if SQL_FORMAT:
    if black_percent > 10:
        pcnt += 1
        output.write('%d, %s, %d\n' % (pcnt, name, 38))
    if gray_percent > 10:
        pcnt += 1
        output.write('%d, %s, %d\n' % (pcnt, name, 37))
    if white_percent > 30:
        pcnt += 1
        output.write('%d, %s, %d\n' % (pcnt, name, 39))
 
# Helper functions follow along with __main__ def
 
def processFolder(folder):
    for image_folder in glob.glob(folder+'*'):
        try:
            folder_images = []
            for image in os.listdir(image_folder):
                if "jpg" in image and "._" not in image:
                    folder_images.append(image)
            folder_images.sort()
            j = os.path.join(image_folder, folder_images[1])
            if SUMMARY_FORMAT:
                print "working: "+j
            i = Image.open(j)
            processImage(i, image_folder.split('/')[-1])
        except:
            pass
 
def processFile(_file):
    i = Image.open(_file)
    processImage(i)
 
if __name__ == "__main__":
    try:
        if 'product-images' not in sys.argv[1]:
            processFile('product-images/'+sys.argv[1])
        else:
            processFile(sys.argv[1])
    except IndexError:
        processFolder(FOLDER)
    output.close()
1 Comment

Blender heartbeat tutorial

10/02/2010

I wrote this about about 2 months ago after playing around with IPO’s combined with a lattice modifier. I thought it would be a good way to create an organic deformation and since you can easily make IPO curves cyclic it was an easy way to make this pumping animation.

I should really go write a whole load of mod_rewrite rules. For now, here’s a link to the tutorial itself in the original format.

No Comments

Old school demo effects: #2 – the raster bar

9/02/2010

I have been using processing for a while now, mainly as a sort of relaxing digression from coding web apps & scripts all day. As a child of the 8-bit era I grew up looking at demos which tended to have a few recurring themes. One of these is the classic “plasma” which I’ve already coded and another was animated “scrollers” which typically consisted of a fuax-3d bar which would bouce up & down the screen.

I created this rough version last night before bed. A scroller class gives it a random start/end color and then a number of intermediate stages are interpolated between them. The brightness of the interpolated colors varies with time to give it a bit more life. Its not really finished yet. Code below the video.

Read the rest of this article »

No Comments

Beginnings of a particle system in processing

1/02/2010

I have been getting more & more into processing and who doesn’t love particles? I’ve started the basis of a little particle system, there are plenty of examples at openprocessing.org but I wanted to write my own as an exercise. It’s been quite some time since I properly used even pretty basic maths for physics so I’ve been enjoying revisting old uni notes & following through my old engineering books.

I have it colliding in a rough way with the walls. There’s no horizontal component to forces yet, it just drifts as time increases rather than falling straight down. It goes crazy as I’m changing the “gravity” throughout. Hopefully this will continue to grow as I add bits and (re)learn the concepts. So far this probably about 100-150 lines of code, not a lot.

No Comments

Blender generative art with halos

31/01/2010

Some time ago when I first started to play with blender, particles where about the only half decent thing I could manage. Whilst working with a little script to draw me some cubes at along a grid (yeah, think city generator), I added a particle system to each one and gave them a random color. When I rendered it I thought it made a pretty cool background and played about with adding more variation.

The key to nice particles in blender is often to have more of them and bump up the alpha. Then enable the mysterious “x-alpha” setting in the halo pipeline. To get that feeling of energy or glowing you normally want to have the alpha quite low and the add setting fairly high.

An example blend file is here: halos.

No Comments

Processing – spiraly line draw thingy

31/01/2010

I’ve been reading through the vector section on the processing.org reference site and quickly played around with one of the examples showing locking to the center point whilst the mouse moves around to draw spirograph style patterns. Hitting spacebar will clear the screen whilst left/right will increase the size of the circular path the target point moves around. Up/Down adjust the line alpha. This is the sort of quick prototyping that makes processing so much fun. Yeah, fun. If I was a kid these days with a linux setup (or really just the opendisc on dvd) I would consider myself lucky. Then again I grew up playing around with assembly on a C64. I don’t think I’d give up those days, being around since the 8bit era (and old enough then to appreciate it) I’m always amazed when I sit down at my linux box at just how far we’ve come.

I’m even more amazed by the huge amount of great open source software. You really do not need to pay or pirate to make money with a computer these days. Especially as a coder. If you’re a .NET person by choice fair enough. I don’t think I could take a job now that side of the industry, I’m pretty much a FOSS and FOSS only sort of person now. I am of course, incredibly lucky to be in that position. A lot of dev’s can’t make those calls and have to work with whats given.

I seem to have gone off on a tangent there. Code follows after the jump. You can paste that into the processing editor and hit play.

Read the rest of this article »

No Comments

Blender Renders

31/01/2010

I’ve been playing with the amazing blender now for just over a year properly. Before that the most I could manage was a few default primitives with flat shading. Then last year I picked up the book Bounce, Tumble & Splash mainly because I wanted to learn a bit more about the particle effects. I was literally transfixed for several days just drawing cubes with particle systems spurting out of each vertex.

After I eventually got bored of the same old renders I thought I would spend some time actually trying to use the fucking program. One year later I’m pretty chuffed with how I’ve come along. Bear in mind I’m a coder all day but I’ve got exposure to some cool 3d guys at work. And I spend a lot of my day coding python so I’ve also started mucking about using Blender for generative art along with processing.

Here is some of my work over the past year. I often find I’ll start out modelling something simple and then it will take over and I’ll spend hours adding new objects, then texturing and adding a bit of animation before playing with the renderer. When you spend a lot of your day writing code and trying to work out whats broke this time I find blender pretty relaxing.

Pretty much all this is done in 2.49b. Now that 2.50 is out (well, a pretty stable alpha) I should really start getting into that. Team blender – I salute you!

Aside from learning how to actually texture things beyond plain grey I also learned the nuances of the animation and sequencing sytems. The IPO thing (how blender keys the animations) actually makes a lot of sense and combined with the physics engine for soft body simulations you can easily create some bouncy, hairy balls :)

Of course, my learning of blender would be nothing if I did not reinvest the new found knowledge into making explosions… Only this time instead of looking like bits of glitter on a silent blue background its a bit more realistic. Creating these things is usually just a case of adding a few particle systems, one textured black and one yellow-ish. Then its a matter of not leaving the particle physics on all their defaults. Pro-tip – make sure you add some fucking rotation. Exploding shrapnel tends not to stay along one particular direction vector.

No Comments

Old school demo effects: #1 – the plasma

31/01/2010

I have finally gotten around to playing with processing – a java based set of libraries and functions for visual programming. It’s really a lot of fun. It’s great for doing quick and easy interactive visualizations. With minimum code you can start drawing simple geometric shapes and when you start throwing around a few sine curves and mouse co-ordinates you’d be surprised what can come out.

One thing I’ve always promised myself I’d code was a plasma effect. A stalwart of the 8-bit demoscene I’m not sure why it’s taken so long for me to get round to actually coding one from scratch. As you can guess, processing made it pretty straightforward. Here’s the result:

This plasma harks back to one of the first group assignments I had at university where we were given an FPGA and we had to load in a picture of Lena and do something with it. The plasma never materialised, instead we ended up doing a convolution kernel. I can remember we had around 2 weeks to do it (teams of 4 or 5) and write a little report. I wrote this in the space of an hour or two.

If you’ve never used it before and have always wanted to do a bit of abstract graphical programming I’d highly recommend it. The core keywords/methods are all pretty sensible and once you’ve worked through a few basic “sketches” the whole thing begins to gel easily and you start thinking less about the code and more about what you want to do on screen.

Here are a few images I’ve created via scanning each sampled point and matching it with others in the image within a threshold. A bezier line then connects the points.

No Comments