Home Data Tutorials Python Graphics: Combining Raster and Vector Pictures

Python Graphics: Combining Raster and Vector Pictures

0
3755
11 min read

 

Python 2.6 Graphics Cookbook

Python 2.6 Graphics Cookbook

Learn Programming & Development with a Packt Subscription

Over 100 great recipes for creating and animating graphics using Python

  • Create captivating graphics with ease and bring them to life using Python
  • Apply effects to your graphics using powerful Python methods
  • Develop vector as well as raster graphics and combine them to create wonders in the animation world
  • Create interactive GUIs to make your creation of graphics simpler
  • Part of Packt’s Cookbook series: Each recipe is a carefully organized sequence of instructions to accomplish the task of creation and animation of graphics as efficiently as possible

Because we are not altering and manipulating the actual properties of the images we do not need the Python Imaging Library (PIL) in this chapter. We need to work exclusively with GIF format images because that is what Tkinter deals with.

We will also see how to use “The GIMP” as a tool to prepare images suitable for animation.

Simple animation of a GIF beach ball

We want to animate a raster image, derived from a photograph.

To keep things simple and clear we are just going to move a photographic image (in GIF format) of a beach ball across a black background.

Getting ready

We need a suitable GIF image of an object that we want to animate. An example of one, named beachball.gif has been provided.

How to do it…

Copy a .gif fle from somewhere and paste it into a directory where you want to keep your work-in-progress pictures.

Ensure that the path in our computer’s fle system leads to the image to be used. In the example below, the instruction, ball = PhotoImage(file = “constr/pics2/beachball.gif”) says that the image to be used will be found in a directory (folder) called pics2, which is a sub-folder of another folder called constr.

Then execute the following code.

# photoimage_animation_1.py
#>>>>>>>>>>>>>>>>>>>>>>>>
from Tkinter import *
root = Tk()

cycle_period = 100

cw = 300 # canvas width
ch = 200 # canvas height
canvas_1 = Canvas(root, width=cw, height=ch, bg=”black”)
canvas_1.grid(row=0, column=1)
posn_x = 10
posn_y = 10
shift_x = 2
shift_y = 1

ball = PhotoImage(file = “/constr/pics2/beachball.gif”)

for i in range(1,100): # end the program after 100 position shifts.
posn_x += shift_x
posn_y += shift_y
canvas_1.create_image(posn_x,posn_y,anchor=NW, image=ball)
canvas_1.update() # This refreshes the drawing on the canvas.
canvas_1.after(cycle_period) # This makes execution pause for 100 milliseconds.
canvas_1.delete(ALL) # This erases everything on the canvas.

root.mainloop()


How it Works

The image of the beach ball is shifted across a canvas. The photo type images always occupy a rectangular area of screen. The size of this box, called the bounding box, is the size of the image. We have used a black background so the black corners on the image of our beach ball cannot be seen.

The vector walking creature

We make a pair of walking legs using the vector graphics. We want to use these legs together with pieces of raster images and see how far we can go in making appealing animations. We import Tkinter, math, and time modules. The math is needed to provide the trigonometry that sustains the geometric relations that move the parts of the leg in relation to each other.

Python Graphics Combining Raster and Vector Pictures

Getting ready

We will be using Tkinter and time modules to animate the movement of lines and circles. You will see some trigonometry in the code. If you do not like mathematics you can just cut and paste the code without the need to understand exactly how the maths works. However, if you are a friend of mathematics it is fun to watch sine, cosine, and tangent working together to make a child smile.

How to do it…

Execute the program as shown in the previous image.

# walking_creature_1.py
# >>>>>>>>>>>>>>>>
from Tkinter import *
import math
import time
root = Tk()
root.title(“The thing that Strides”)

cw = 400 # canvas width
ch = 100 # canvas height
#GRAVITY = 4
chart_1 = Canvas(root, width=cw, height=ch, background=”white”)
chart_1.grid(row=0, column=0)

cycle_period = 100 # time between new positions of the ball (milliseconds).

base_x = 20
base_y = 100
hip_h = 40
thy = 20
#===============================================
# Hip positions: Nhip = 2 x Nstep, the number of steps per foot per stride.
hip_x = [0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 60, 60] #15
hip_y = [0, 8, 12, 16, 12, 8, 0, 0, 0, 8, 12, 16, 12, 8, 0] #15

step_x = [0, 10, 20, 30, 40, 50, 60, 60] # 8 = Nhip
step_y = [0, 35, 45, 50, 43, 32, 10, 0]

# The merging of the separate x and y lists into a single sequence.
#==================================
# Given a line joining two points xy0 and xy1, the base of an isosceles triangle,
# as well as the length of one side, “thy” . This returns the coordinates of
# the apex joining the equal-length sides.

def kneePosition(x0, y0, x1, y1, thy):
theta_1 = math.atan2((y1 – y0), (x1 – x0))
L1 = math.sqrt( (y1 – y0)**2 + (x1 – x0)**2)
if L1/2 < thy:
# The sign of alpha determines which way the knees bend.
alpha = -math.acos(L1/(2*thy)) # Avian
#alpha = math.acos(L1/(2*thy)) # Mammalian
else:
alpha = 0.0
theta_2 = alpha + theta_1
x_knee = x0 + thy * math.cos(theta_2)
y_knee = y0 + thy * math.sin(theta_2)
return x_knee, y_knee

def animdelay():
chart_1.update() # This refreshes the drawing on the canvas.
chart_1.after(cycle_period) # This makes execution pause for 200 milliseconds.
chart_1.delete(ALL) # This erases *almost* everything on the canvas.
# Does not delete the text from inside a function.
bx_stay = base_x
by_stay = base_y

for j in range(0,11): # Number of steps to be taken – arbitrary.
astep_x = 60*j
bstep_x = astep_x + 30
cstep_x = 60*j + 15
aa = len(step_x) -1
for k in range(0,len(hip_x)-1):
# Motion of the hips in a stride of each foot.
cx0 = base_x + cstep_x + hip_x[k]
cy0 = base_y – hip_h – hip_y[k]
cx1 = base_x + cstep_x + hip_x[k+1]
cy1 = base_y – hip_h – hip_y[k+1]
chart_1.create_line(cx0, cy0 ,cx1 ,cy1)
chart_1.create_oval(cx1-10 ,cy1-10 ,cx1+10 ,cy1+10, fill=”orange”)

if k >= 0 and k <= len(step_x)-2:
# Trajectory of the right foot.
ax0 = base_x + astep_x + step_x[k]
ax1 = base_x + astep_x + step_x[k+1]
ay0 = base_y – step_y[k]
ay1 = base_y – step_y[k+1]
ax_stay = ax1
ay_stay = ay1

if k >= len(step_x)-1 and k <= 2*len(step_x)-2:
# Trajectory of the left foot.
bx0 = base_x + bstep_x + step_x[k-aa]
bx1 = base_x + bstep_x + step_x[k-aa+1]
by0 = base_y – step_y[k-aa]
by1 = base_y – step_y[k-aa+1]
bx_stay = bx1
by_stay = by1

aknee_xy = kneePosition(ax_stay, ay_stay, cx1, cy1, thy)
chart_1.create_line(ax_stay, ay_stay ,aknee_xy[0], aknee_xy[1], width = 3, fill=”orange”)
chart_1.create_line(cx1, cy1 ,aknee_xy[0], aknee_xy[1], width = 3, fill=”orange”)

chart_1.create_oval(ax_stay-5 ,ay1-5 ,ax1+5 ,ay1+5, fill=”green”)
chart_1.create_oval(bx_stay-5 ,by_stay-5 ,bx_stay+5 ,by_stay+5, fill=”blue”)

bknee_xy = kneePosition(bx_stay, by_stay, cx1, cy1, thy)
chart_1.create_line(bx_stay, by_stay ,bknee_xy[0], bknee_xy[1], width = 3, fill=”pink”)
chart_1.create_line(cx1, cy1 ,bknee_xy[0], bknee_xy[1], width = 3, fill=”pink”)

animdelay()

root.mainloop()


How it works…

Without getting bogged down in detail, the strategy in the program consists of defning the motion of a foot while walking one stride. This motion is defned by eight relative positions given by the two lists step_x (horizontal) and step_y (vertical). The motion of the hips is given by a separate pair of x- and y-positions hip_x and hip_y.

Trigonometry is used to work out the position of the knee on the assumption that the thigh and lower leg are the same length. The calculation is based on the sine rule taught in high school. Yes, we do learn useful things at school!

The time-animation regulation instructions are assembled together as a function animdelay().

There’s more

In Python math module, two arc-tangent functions are available for calculating angles given the lengths of two adjacent sides. atan2(y,x) is the best because it takes care of the crazy things a tangent does on its way around a circle – tangent ficks from minus infnity to plus infnity as it passes through 90 degrees and any multiples thereof.

A mathematical knee is quite happy to bend forward or backward in satisfying its equations. We make the sign of the angle negative for a backward-bending bird knee and positive for a forward bending mammalian knee.

More Info Section 1

This animated walking hips-and-legs is used in the recipes that follow this to make a bird walk in the desert, a diplomat in palace grounds, and a spider in a forest.

Bird with shoes walking in the Karroo

We now coordinate the movement of four GIF images and the striding legs to make an Apteryx (a fightless bird like the kiwi) that walks.

Python Graphics Combining Raster and Vector Pictures

Getting ready

We need the following GIF images:

  • A background picture of a suitable landscape
  • A bird body without legs
  • A pair of garish-colored shoes to make the viewer smile
  • The walking avian legs of the previous recipe

The images used are karroo.gif, apteryx1.gif, and shoe1.gif. Note that the images of the bird and the shoe have transparent backgrounds which means there is no rectangular background to be seen surrounding the bird or the shoe. In the recipe following this one, we will see the simplest way to achieve the necessary transparency.

How to do it…

Execute the program shown in the usual way.

# walking_birdy_1.py
# >>>>>>>>>>>>>>>>
from Tkinter import *
import math
import time
root = Tk()
root.title(“A Walking birdy gif and shoes images”)
cw = 800 # canvas width
ch = 200 # canvas height
#GRAVITY = 4
chart_1 = Canvas(root, width=cw, height=ch, background=”white”)
chart_1.grid(row=0, column=0)

cycle_period = 80 # time between new positions of the ball (milliseconds).
im_backdrop = “/constr/pics1/karoo.gif”
im_bird = “/constr/pics1/apteryx1.gif”
im_shoe = “/constr/pics1/shoe1.gif”
birdy =PhotoImage(file= im_bird)
shoey =PhotoImage(file= im_shoe)
backdrop = PhotoImage(file= im_backdrop)
chart_1.create_image(0 ,0 ,anchor=NW, image=backdrop)
base_x = 20
base_y = 190
hip_h = 70
thy = 60
#==========================================
# Hip positions: Nhip = 2 x Nstep, the number of steps per foot per stride.
hip_x = [0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 60, 60] #15
hip_y = [0, 8, 12, 16, 12, 8, 0, 0, 0, 8, 12, 16, 12, 8, 0] #15

step_x = [0, 10, 20, 30, 40, 50, 60, 60] # 8 = Nhip
step_y = [0, 35, 45, 50, 43, 32, 10, 0]

#=============================================
# Given a line joining two points xy0 and xy1, the base of an isosceles triangle,
# as well as the length of one side, “thy” this returns the coordinates of
# the apex joining the equal-length sides.

def kneePosition(x0, y0, x1, y1, thy):
theta_1 = math.atan2(-(y1 – y0), (x1 – x0))
L1 = math.sqrt( (y1 – y0)**2 + (x1 – x0)**2)
alpha = math.atan2(hip_h,L1)
theta_2 = -(theta_1 – alpha)
x_knee = x0 + thy * math.cos(theta_2)
y_knee = y0 + thy * math.sin(theta_2)
return x_knee, y_knee

def animdelay():
chart_1.update() # Refresh the drawing on the canvas.
chart_1.after(cycle_period) # Pause execution pause for X millise-conds.
chart_1.delete(“walking”) # Erases everything on the canvas.

bx_stay = base_x
by_stay = base_y

for j in range(0,13): # Number of steps to be taken – arbitrary.
astep_x = 60*j
bstep_x = astep_x + 30
cstep_x = 60*j + 15
aa = len(step_x) -1
for k in range(0,len(hip_x)-1):
# Motion of the hips in a stride of each foot.
cx0 = base_x + cstep_x + hip_x[k]
cy0 = base_y – hip_h – hip_y[k]
cx1 = base_x + cstep_x + hip_x[k+1]
cy1 = base_y – hip_h – hip_y[k+1]
#chart_1.create_image(cx1-55 ,cy1+20 ,anchor=SW, image=birdy, tag=”walking”)

if k >= 0 and k <= len(step_x)-2:
# Trajectory of the right foot.
ax0 = base_x + astep_x + step_x[k]
ax1 = base_x + astep_x + step_x[k+1]
ay0 = base_y – 10 – step_y[k]
ay1 = base_y – 10 -step_y[k+1]
ax_stay = ax1
ay_stay = ay1

if k >= len(step_x)-1 and k <= 2*len(step_x)-2:
# Trajectory of the left foot.
bx0 = base_x + bstep_x + step_x[k-aa]
bx1 = base_x + bstep_x + step_x[k-aa+1]
by0 = base_y – 10 – step_y[k-aa]
by1 = base_y – 10 – step_y[k-aa+1]
bx_stay = bx1
by_stay = by1

chart_1.create_image(ax_stay-5 ,ay_stay + 10 ,anchor=SW, im-age=shoey, tag=”walking”)
chart_1.create_image(bx_stay-5 ,by_stay + 10 ,anchor=SW, im-age=shoey, tag=”walking”)

aknee_xy = kneePosition(ax_stay, ay_stay, cx1, cy1, thy)
chart_1.create_line(ax_stay, ay_stay-15 ,aknee_xy[0], aknee_xy[1],
width = 5, fill=”orange”, tag=”walking”)
chart_1.create_line(cx1, cy1 ,aknee_xy[0], aknee_xy[1], width = 5,
fill=”orange”, tag=”walking”)

bknee_xy = kneePosition(bx_stay, by_stay, cx1, cy1, thy)
chart_1.create_line(bx_stay, by_stay-15 ,bknee_xy[0], bknee_xy[1],
width = 5, fill=”pink”, tag=”walking”)
chart_1.create_line(cx1, cy1 ,bknee_xy[0], bknee_xy[1], width = 5,
fill=”pink”, tag=”walking”)
chart_1.create_image(cx1-55 ,cy1+20 ,anchor=SW, image=birdy, tag=”walking”)
animdelay()

root.mainloop()


How it works…

The same remarks concerning the trigonometry made in the previous recipe apply here. What we see here now is the ease with which vector objects and raster images can be combined once suitable GIF images have been prepared.

There’s more…

For teachers and their students who want to make lessons on a computer, these techniques offer all kinds of possibilities like history tours and re-enactments, geography tours, and, science experiments. Get the students to do projects telling stories. Animated year books?

NO COMMENTS

LEAVE A REPLY

Please enter your comment!
Please enter your name here