Tutorial: How to create a nailboard – part 2 (loading a picture)

[toc]

Introduction

This part of the tutorial series will work out how to load an image to the nailboard created in How to create a nailboard – part 1 (creating the nails) so that it looks like in my video keep on nailin’:
A nailboard example.

As expected no project tooks the way you thought it will go when you started it. When i began to create the nailboard i worked with blender 2.49b. Now blender 2.5 is out and i thought it will be quite easy to port the scripts to the new version. You already guess it – this was not the case 😀 !

In blender 2.5 runs a python interpreter of the version 3.x your python scripts. In blender 2.49b this was done by a python interpreter version 2.x. And here comes the point where things get tricky: there is no “Python Image Library”-package for python 3.x. One can compile the source by himself and use it with his own python 3.x, but cause blender has its own python interpreter the including of your own PIL-compilation gets harder. Cause i want to keep things as simple as possible, i don’t want you to create your own blender build or get in touch with the ctypes-module… so we will go a little detour and have an easier way (we will use the old python version outside blender for preparing the image data and load it in blender to apply it to the nails). At the end of this part of the tutorial i will give you the 2.5 and the 2.49b files for comparison. The tutorial will stay at the blender version 2.5.

Overview

The last part of this tutorial series has focused on the creation of our nails. There every nail got an unique name. In this part we will discuss the scripts which load an image to the nailboard.

In a previous post i wrote about another (and faster) way to come to a nailboard. I will discuss the differences short at the end of this post.

The idea

As mentioned before we have to go a little detour. So my former blender 2.49b script is divided into two parts: one script to read the input image and one script to apply the gained information to our nailboard. The second script not only applies the height values to the several nails, it also saves them to the graphs, which where in former blender versions the ipo-curves.

The scripts

As in the first tutorial part i will go from top to bottom through the scripts.

The script generator script

Let us begin with the main function “generateScript” of the generation script. Here it is:

#!/usr/bin/python

# Script to generate the imageload
...

import os
import Image

size = (102,76)

...

def generateScript( in_file, base_file, out_file, frame ):
base = file2string( base_file )
s = prepareImage( in_file, frame )
string2file( out_file, base + s )

generateScript( 'beaker_full.png', 'base.py', 'tmp.py', 1 )

As you can see our main function has four parameters: the name of the image, the name of the file in which the header for our loading sequence is placed, the name of our generated image loading script and the frame number where the image should appear. The first command reads, like the function name says, the base file to the string “base”. The second command reads the image and prepares a string with commands to set the nails. We will see this soon. The last command finally writes the concatenated strings to the given file. I will omit the file handling here to keep things short.

Now we come back to the function “prepareImage”. Here it is:

def prepareImage( name, frame ):
img = Image.open( name )
img.thumbnail( size )

s = ""
for x in range( 0, size[0] ):
for y in range( 0, size[1] ):
colour = getPixel( img, x, y )
s += prepareString( x, y, frame, colour )
return s

The first two commands open the image file and scale it down to the previous defined dimensions “size”. This is quite useful, so we don’t have to scale for ourselves. I have chosen this dimensions (for the nailboard and the “size” variable) cause now we can simply take an image with 1024×768 pixels. I haven’t try what happens if you take an image with other dimensions, but i guess it will work too ;).

The function “prepareString” returns a string with a python command which looks like this:

setNail( 5, 5, 1, 0.329411764706)

Where the first two integers are the coordinates on the nailboard (here (5,5)), the third value is the frame in which the height value will be displayed (in a domain from zero upto one, where zero means the bottom value for a nail and one means the top value for a nail).

Let us now take a look on the results of the “getPixel” function:

def getPixel( img, x, y ):
colour = 0
if ( img.mode == 'P' ):
colour = float( img.getpixel( ( x, y ) ) )
elif ( img.mode == 'L' ):
colour = img.getpixel( ( x, y ) ) / float( 255 )
elif ( img.mode == 'RGB' ):
rgb = img.getpixel( ( x, y ) )
colour = ( rgb[0] + rgb[1] + rgb[2] ) / float( 3*255 )
return colour

It is a case differentiation and scales the pixel values of the image to the domain between zero and one. The cases i implemented are the full colour, the greyscale and the black and white images. This is necessary if you want to use the script easily with arbitrary image types – here are three basic examples:

>>> im=Image.open('beaker.png')
>>> im.mode
'RGB'
>>> im.getpixel((1,1))
(175, 73, 5)

>>> im=Image.open('beaker256.png')
>>> im.mode
'L'
>>> im.getpixel((1,1))
90

>>> im=Image.open('beaker2.png')
>>> im.mode
'P'
>>> im.getpixel((1,1))
1

Applying the script

The generated script is written to a file with name “tmp.py”. To generate this script you need the base script, where the header with the functions for the generated script lies in. Open a shell and change to the directory where your image and your scripts are in. Then type

./preparePic.py

and hit enter. If you have not installed python 2.6, then install it by typing

sudo apt-get install python2.6

and run the script again. If all went well, you have now the file “tmp.py”. Test it by typing

ls

to your shell.

The generated script

The last pieces of code i want to look at are parts of the generated script. You already know the functions “unselectAll”, “floatRange” and “moveToLayer” from the last part of this tutorial series. We have only to look at

def getNail( x, y ):
str_name = 'nail' + '_' + str(x) + '_' + str(y)
return bpy.data.objects[ str_name ]

def setNail( x, y, frame, height ):
unselectAll()

max = 3.5
nail = getNail( x, y )
nail.location.z = height * max
nail.keyframe_insert( data_path="location", frame=frame, index=2)

# after this line the generated part starts
# -----------------------------------------------------------------

setNail(0,0,1,0.329411764706)
...

The generated part of the script is a list of calls of the “setNail” function. It takes the nailboard coordinates x and y, the frame number and the new height of the nail. The function “getNail” helps us to get the pointer to the correct nail. The value max is the maximum height of your nails. If you want to use another domain than 0..3,5 correct it here (also the lower limit could be moved at the position where “height * max” stands)! To end up with a positioned nail we set it by the “nail.location.z” value. Last, but nearly equally important, we set a new keyframe at our frame to the location.

Running the generated script

Open your blend file with your nailboard from the last part of this tutorial series. Then open a Text Editor and the generated script in it:
add a plane

And finally run the script by hitting “Alt+P”. This will take a while…

Now you are able to load any image to your nailboard!

Conclusion

I assume this may be interesting points:

  • as usual there are multiple ways to come to a good result (this one and the displacement method),
  • both lead to displayed images,
  • displacement method is faster realized,
  • i have not compared running/rendering times,
  • if you set two frames (at least two frames away from each other), with this method, then the blender internal graphs care for our interpolation,
  • the latter point is important for more realistic movies,
  • the displacement method leaves you alone with this (i haven’t tried to reach smooth movements by interpolation between two images with a video program – if you only want transfer two images, this will not be hard, but if you want to have smooth nail movements in a movie sequence then this could get harsh).

What i learned

  • i will never start a tutorial before i’m shure everything works as expected ;),
  • a very little bit of the new blender 2.5 python API and the new console,
  • an important thing about blender: the python interpreter is hard coded into it,
  • next time i animate something like a nailboard, i choose at first the music and then go and make an animation storyboard and finally
  • sharing information is fun and makes you learn more about the systems you use!

Downloads

Here you can download the two scripts:

 

I hope you had fun and learned something! If you liked this tutorial series or have any suggestions, hints and/or critiques, let me know it and write a comment and/or a mail!

Tutorial: How to create a nailboard – remark, an alternative solution

In this post i want to show you a fast alternative way how you could create a nailboard like i showed you in my former post. I got the idea from Wefyb at the BlenderArtists forum (thanks for this 😉 ). I will not discuss it too deep, because it is really easy to apply. You can get more information about the DupliVerts method in the blender documentation. I describe the solution in blender 2.5.

Let’s go:
When you have modeled your nail you add a plane:
add a plane

Then parent the plane to the nail by

  • selecting the nail,
  • select the plane too (holding shift) and
  • pressing Ctrl+P and select “Object”.

Now select the plane and go to the “Object Properties”. There is a submenu “Duplication”. Here you choose “Verts”. If all went well you have this situation:
add a plane

Now apply your imagesize by subdividing/extruding the plane in Editmode until it has the exact the same dimensions in vertices like your image has pixels. For this tutorial i only made two subdivisions, which leads to a 5×5 nailboard, you will have to scale your nails and your plane a bit, to adjust the whole thing:
add a plane

The next step is to add an displacement modifier to the plane, set the Midlevel to “0” and the direction to “Z”:
add a plane

Add a new texture:
add a plane

Go to the texture properties and set the type to “Image or Movie” and load an image:
add a plane

If all went well you have implemented your nailboard really fast. Only things to do are the modeling of the nailboard body and the scaling of the heights, which are controlled by the “Strength” value of the displacement modifier. At a later post i will discuss the difference between this kind of nailboard generation and “my way”.

I hope you liked this post. If so or if you have questions or hints, let me know it and write a comment.

MySQL database backup script

Using the scripts

In another post i wrote two scripts which allow you comfortable to save and restore your disk under ubuntu (other linux probably will work too 😉 ). Now i give you similar scripts for your MySQL databases. I use the plain scripts from the WordPress Backups page and use python 3.1 again for shortness and readability of code.

Again the warning:
Don’t use them mindless, you could damage all your recent work or worse! I don’t take responsibility for the effects of this scripts, you use them on your own response!

You have to give the “db2file.py” a string with a description like this:

./db2file.py 'before installing the newest updates'

and it will create a packed file called:

001__17_5_2011__before_installing_the_newest_updates.bak.sql.bz2

with an automatic incremented number and the date.

To decompress the file use:

./file2db.py 001__17_5_2011__before_installing_the_newest_updates.bak.sql.bz2

You can define another database name and user by the -u and -d options, here are the help outputs:

Usage: db2file.py description_string

Options:
  -h, --help            show this help message and exit
  -u USER, --user=USER  database user name
  -d DATABASE, --database=DATABASE
                        database name
Usage: file2db.py filename

Options:
  -h, --help            show this help message and exit
  -u USER, --user=USER  database user name
  -d DATABASE, --database=DATABASE
                        database name

If you have ideas or hints on the scripts or even find them usefull, let me know it and write a comment.

Download

You can download them here:
db2file.py
file2db.py

If you have ideas or hints on the scripts or even find them usefull, let me know it and write a comment.

Ubuntu backup scripts

[toc]

Using the scripts

There are many backup scripts out there for linux. I wrote two on base of a tar with bzip2 and nice (giving you the ability to use your box while [de]compressing by setting the priority of the backups to “lowest”) in python 3.1.

Don’t use them mindless, you could damage all your recent work or worse! I don’t take responsibility for the effects of this scripts, you use them on your own response!

You have to give the “disk2file.py” a string with a description like this:

./disk2file.py 'before installing the newest updates'

and it will create a packed file called:

001__16_5_2011__before_installing_the_newest_updates.tar.bz2

with an automatic incremented number and the date.

To decompress the file use:

./file2disk.py 001__16_5_2011__before_installing_the_newest_updates.tar.bz2

You can define another directory to compress and decompress and a comma separated list of directories to exclude, here are the help outputs:

Usage: disk2file.py description_string

Options:
  -h, --help            show this help message and exit
  -d DIRECTORY, --directory=DIRECTORY
                        directory which will be saved (default='/')
  -e EXCLUDE, --exclude=EXCLUDE
                        directories to exclude (separated by comma,
                        default='['/proc', '/lost+found', '/media', '/mnt',
                        '
/sys', '/var/backup*']')
Usage: file2disk.py filename

Options:
  -h, --help            show this help message and exit
  -d DIRECTORY, --directory=DIRECTORY
                        directory where the backup will be copied
                        (default='/')

If you have ideas or hints on the scripts or even find them usefull, let me know it and write a comment.

Download

You can download them here:
disk2file.py
file2disk.py

If you have ideas or hints on the scripts or even find them usefull, let me know it and write a comment.

Tutorial: How to create a nailboard – part 1 (creating the nails)

[toc]
In this Tutorialseries i’m going to show you how to create a nailboard, like in my animation keep on nailin’ and load a picture to it, so that it looks like this:
A nailboard example.
There will be two parts, one in which you will learn how to actually create the nailboard and one with the aim of loading a picture to it. Maybe there will be a third part about loading movies to it, but i’m not sure about this.

Introduction

Things that i assume:

  • you use an ubuntu (maybe i add windows later on, i’m not sure about this)
  • you’re have installed and are familiar with blender 2.5,
  • you know how to build a nail in blender (drawing a curve, convert it to mesh and spin it)
    a curve for the nail object
  • and have done it before starting the programming (important: give the object the name “nail”) or download the file at the end of the tutorial
  • you know what the programming language python is
  • you have installed the python-image package:
    • if you’re not sure try
      import Image

      at the python console

    • if you get an error type
      sudo apt-get install python-imaging

      to install it from a shell

    • if you get no error, the package is installed and works

Ok, let us begin! I divided the tutorial and the program into two parts after the old principle “divide and conquer”. The first thing to do is the creation of a nailboard where every single nail could get a several height value. Than one has only to load a image and convert the colour values into height values.

My first idea was the array modifier:
the array modifier
But it doesn’t support the generation of several objects with individual names, so i decided to write a script for this task (it was clear that the second part will need a script, so this choice was easy 😉 ). The complete script and a .blend file of my hires nail are at the end of this tutorial.

The basic idea

The underlying idea is to name the several nails with the base name followed by the coordinates in x and y of our array. I decided to separate the parts of the names with a underscore, so that it’s clearer that the name is a string. In this example the nail with the coordinates x=1 and y=0 is selected:
the naming conventions
The described script will generate a nailboard array of the size 102×76, so that we can easily scale down a 1024×768 image by scaling factor 10% and load it to our nailbaord.

Let us now go through the script! I will go topically from top to bottom, cause i like it more than asking myself “why i’m doing this right now?”.

The main function

The main function of the generation script is “createField”. At first i will give it to you and than discuss the details:

import bpy

scn  = bpy.context.scene
nail = bpy.data.objects["nail"]

...

def createField( object, x_start, width, y_start, depth, step ):
  unselectAll()
  object.select = 1
  moveToLayer( object, 0 )

  str_base = object.name
  str_sep = '_'

  y_cnt = y_start
  for y in floatRange( y_start * step, depth, step ):
    x_cnt = x_start
    for x in floatRange( x_start * step, width, step ):
      print( x_cnt,y_cnt )
      bpy.ops.object.duplicate( linked=True )

      name = str_base + str_sep + str(x_cnt) + str_sep + str(y_cnt)
      setObjectValues( scn.objects.active, name, x, y )

      x_cnt += 1
    y_cnt += 1
  moveToLayer( object, 1 )

createField( nail, 0, 102, 0, 76, 0.5 )

If you want to type it or just want to copy and paste it to your own file, than just open a “Text Editor” and fill it with the script parts. The later declared functions belong into the part where the “…” are!
a Text Editor

Let’s go into the details of this snippet. At first we look at the prefix:

import bpy

scn  = bpy.context.scene
nail = bpy.data.objects["nail"]

The code does the following:

  • with
    import bpy

    the blender library functionality is included into the python script,

  • scn  = bpy.context.scene

    gives us a shortcut to the scene object and

  • nail = bpy.data.objects["nail"]

    grabs the object with the name “nails”.

The function “createField” takes the following parameters:

  • a pointer to the object, which should be arrayed, called “object”,
  • starting points “x_start” and “y_start” where the naming of the nails should start,
  • dimensions “width” and “depth”, which declare how big the generated array will be, and
  • a value “step”, which defines how big the distance between every two neighbored nails is.

The first thing the function “createField” does, is to call a function “unselectAll”. Like the name says it unselects all objects of the scene. The code to do this is here (if you copy and paste it in your own file, put it above the function “createField”):

def unselectAll():
    bpy.ops.object.select_all( action = 'DESELECT' )

It walks through all objects and apllies the action “DESELECT” to each one.

The next two lines select the nailmesh and move it to the layer zero. I added this, cause the last step the function “createField” does, is to move the nail to the layer 1, so that the original object isn’t overlaying with the new nail at the first position.

  object.select = 1
  moveToLayer( object, 0 )

The function “moveToLayer” looks like this:

def moveToLayer( object, layer ):
    layers = [False]*20
    layers[layer] = True
    object.layers = layers

In blender python the layers, where an object is visible, are organized in an bool array. Cause blender has 20 layers the field has the length 20. All other layers are set to False and our wished layer gets the value True.

After this the distinct naming of every nail is prepared:

  str_base = object.name
  str_sep = '_'

We decide to use the name “nail” of our nail object as base and define the separator ‘_’.

The main loop

Having done all this arrangements we can go into the two-layered loop. It generates the two-dimensional array of nails. Therefore the outer loop walks through the y-axis and the inner loop through the x-axis. They both use the function “floatRange” to generate the values they traverse:

def floatRange( start, n, step ):
    val = start
    list = []
    for i in range(0,n):
        list.append( val )
        val += step
    return list

This function is a self written equivalent to the normal python function “range” and delivers a float range of values:

>>> floatRange(0,5,0.25)
[0, 0.25, 0.5, 0.75, 1.0]

The body of the inner loop looks like this:

  print( x_cnt,y_cnt )
  bpy.ops.object.duplicate( linked=True )
     
  name = str_base + str_sep + str(x_cnt) + str_sep + str(y_cnt)
  setObjectValues( scn.objects.active, name, x, y )

It does the following things:

  • it prints the actual generated nail coordinates of our nailboard (x,y),
  • then copies the nail as an linked object (important, so that every nail changes if you realize that the nailboard is getting to big for your architecture and saves much of disk space),
  • creates the name for the nail and finally
  • sets the calculated values to the actual generated nail in the function “setObjectValues”.

The last thing we will watch is the function “setObjectValues”:

def setObjectValues( object, name, x, y ):
    object.name = name
    object.location.x = x
    object.location.y = y

Its parameters are a pointer to the given object (our original nail), the name of the actual generated nail and the real coordinates for the nail.

The last step

After typing the whole text to your blender Text Editor or just copy pasting it, i recommend that you save your work and start it in a blender with an open console. Therefore open a console and type

blender

or move to your blender directory and call it.

Having done this, position the mouse cursor over the Text Editor and hit Alt+p. The generation takes a while and if you sit on an older computer you maybe have to simplify the geometry of the mesh. For the animation i did it too, cause it needed too much time for every frame. To watch the progress, lokk into the console window. If you want to stop the script, go to the console and hit Alt+C. My experience is, the more nails the blend file has, the slower every new nail gets created. It could take real long time – lean back and let it work :)!

Conclusion

After walking through the genration script i hope no questions are open and you understand what we’ve done here. If something is unclear, please leave a comment. The next part of the tutorial series will discover the loading of an image to our newly generated nailboard. The only things you have to do are the modelling of the rest of the scene and the nailboard (the glass, the feet and the bottom).

And know, as promised, the downloads for the lazy ones: