The ProcGraph tutorial¶
Welcome to the ProcGraph tutorial! This tutorial will guide you through the first steps with ProcGraph, from the basic syntax, up to the recommended design patterns and how to document your creations.
Even though it is fine to read this on the web, cutting&paste the examples to your terminal or editor, it is advised that you download the ProcGraph source code. There, in the directory docs/tutorial, you will find all these scripts and resources in separate files ready to run.
Basic syntax¶
The basic ProcGraph metaphors are blocks and signals. A model is an interconnection of blocks, and it is specified using ProcGraph‘s model language. This language is very much inspired by ASCII art; the idea being that a graphical representation of blocks is useful to understand your models, yet, the fact that everything is plain text makes the source clear, and editing fast.
Enough words! The first model that we consider can be found in the file tutorial00_basics.pg:
# Read from a .mp4 file, write to a .avi file.
|mplayer file="coastguard.mp4"| --> |mencoder vbitrate=1000 file="coastguard00.avi"|
This model is composed by two blocks: Block mplayer and Block mencoder. An instantiation of a block is specified using the syntax |block-type param=value|, with multiple parameters allowed. A complete list of the blocks, with documentation on what parameters they accept, is available at ProcGraph core blocks; this tutorial will explain also how to create your own blocks.
The two blocks are connected by the arrow -->. This means that all signals from the first block flow into the second. In this case, Block mplayer has only one output, and Block mencoder has only one input, but we will see that blocks can be very flexible in how many signals they accept or produce.
It’s time to run this model. As you might have guessed, the model transcodes one video file to another format. Albeit ProcGraph is pretty much data-agnostic, most of the examples involve reading and manipulating a video, as it is fun to have an immediate visual feedback of what you are doing. All the scripts refer to the file coastguard.mp4, which should be in your current directory; you can, of course, use any video you want.
ProcGraph has both an API to run modules from inside your Python code (see Executing ProcGraph models), and a command-line program that runs the models for you, called pg. In this tutorial, we are going to use the latter. If ProcGraph is properly installed, you can run a model using the syntax pg <model name>. If you saved the above model to a file tutorial00_basics.pg, then you can run it using:
$ pg tutorial00_basics
The expected output is coastguard00.avi.
Naming signals¶
We will see that ProcGraph models can become quite complex. In particular, you are not limited to have only one series of blocks; you can process the same signal in a parallel pathway. So one necessary ability is being able to give names to signals so that you can refer to them later.
You can see an example of this in tutorial01_signals.pg:
# Model demonstrating the syntax for naming signals.
|mplayer file="coastguard.mp4"| --> rgb
rgb --> |mencoder vbitrate=100 file="coastguard01.avi"|
Here, we give the name rgb to the output of the first block. Then, we can refer to this signal later, and use it as input to the second block.
In general, if a block has multiple outputs, you would use the syntax:
|block| --> signal1, signal2, signal3
to give the various outputs names.
An extended example¶
This section must still be written.
Passing configuration variables¶
This section must still be written.
# Show how to use configuration
config in "Input file"
config out "Output file"
|mplayer file=$in| --> rgb --> |mencoder file=$out|
Organizing code in multiple models¶
This section must still be written.
# Show how to put multiple models, and how to write
--- model tutorial04_models
''' The master model '''
config in "Input file"
config out "Output file"
|mplayer file=$in| --> |tutorial04_filter| --> |mencoder file=$out|
--- model tutorial04_filter
''' The filtering model '''
input rgb "Input image"
output processed "The processed image"
|input name=rgb| --> |posterize levels=3| --> |output name=processed|
Shortcuts for complex configuration¶
This section must still be written.
# Show how to put multiple models, and how to write
--- model tutorial05_config_advanced
''' The master model '''
config in "Input file"
config out "Output file"
config levels = 3 "Number of channels for posterization."
|player:mplayer| --> |tut:tutorial05_filter| --> |encoder:mencoder file=$out|
player.file = $in
tut.levels = $levels
encoder.file = $out
--- model tutorial05_filter
''' The filtering model '''
input rgb "Input image"
output processed "The processed image"
config levels = 3 "Number of channels for posterization."
|input name=rgb| --> |posterize| --> |output name=processed|
# We can use the block type if there is no confusion
posterize.levels = $levels
Explicit signal routing¶
This section must still be written.
# Given a block name, we can route the signal
# Useful for doing different things with the same model
|player:mplayer file="coastguard.mp4"| --> |mencoder file="coastguard.avi"|
player.video --> |mencoder file="coastguard06.avi"|
# Also by signal number (0: first output)
# player.0 --> |mencoder file="coastguard06.avi"|
Creating simple blocks from Python functions¶
This section must still be written.
from procgraph import simple_block
@simple_block
def green_channel(rgb):
green = rgb[:,:,1]
rgb[:,:,0] = green
rgb[:,:,2] = green
return rgb
Adding configuration to simple blocks¶
This section must still be written.
import numpy
from procgraph import simple_block
@simple_block
def choose(rgb, channel=0):
v = rgb[:,:,channel]
result = numpy.dstack((v,v,v))
return result
--- model tutorial08_simple_blocks
import tutorial08_blocks
|player:mplayer file="coastguard.mp4"| --> rgb
rgb --> |choose channel=0| --> processed
processed --> |mencoder file="coastguard08.avi"|
Best practices for documenting simple blocks¶
This section must still be written.
--- model tutorial09_best_practices
''' Same as tutorial8. '''
import tutorial09_blocks
|player:mplayer file="coastguard.mp4"| --> rgb
rgb --> |choose channel=0| --> red
rgb --> |choose channel=1| --> green
rgb --> |choose channel=2| --> blue
rgb, red, green, blue --> |sync| --> |grid cols=2| --> processed
processed --> |mencoder file="coastguard09.avi"|
import numpy
from procgraph import simple_block, BadConfig
@simple_block
def choose(rgb, channel=0):
''' Chooses a channel from an rgb image and replicates it
over the other two.
Raises an error if ``channel`` is invalid.
:param rgb: Input image.
:param channel: Which channel to choose.
:return: processed: The processed image.
'''
if not channel in [0,1,2]:
raise BadConfig('Invalid channel specified.', config='channel')
v = rgb[:,:,channel]
return numpy.dstack((v,v,v))
Creating stateful blocks from Python classes¶
This section must still be written.
from procgraph import Block
class Psychedelic(Block):
Block.alias('psychedelic')
Block.input('rgb', 'An RGB image.')
Block.output('processed', 'The processed image.')
def init(self):
self.channel = 0
def update(self):
self.channel = (self.channel + 1) % 3
rgb = self.input.rgb.copy()
for i in [0, 1, 2]:
if i != self.channel:
rgb[:,:,i] = 0
self.output.processed = rgb
--- model tutorial10_stateful_blocks
import tutorial10_blocks
|mplayer file="coastguard.mp4"|-->|psychedelic|-->|mencoder file="coastguard10.avi"|