tracksperanto 2.1.1 → 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. data/.gemtest +0 -0
  2. data/DEVELOPER_DOCS.rdoc +41 -39
  3. data/History.txt +7 -0
  4. data/Manifest.txt +3 -1
  5. data/{README.txt → README.rdoc} +11 -13
  6. data/Rakefile +3 -1
  7. data/lib/export/nuke_script.rb +3 -2
  8. data/lib/import/base.rb +20 -31
  9. data/lib/import/boujou.rb +4 -4
  10. data/lib/import/equalizer3.rb +5 -5
  11. data/lib/import/equalizer4.rb +3 -4
  12. data/lib/import/flame_stabilizer.rb +8 -20
  13. data/lib/import/match_mover.rb +3 -4
  14. data/lib/import/maya_live.rb +4 -4
  15. data/lib/import/nuke_grammar/utils.rb +32 -0
  16. data/lib/import/nuke_script.rb +7 -37
  17. data/lib/import/pftrack.rb +5 -5
  18. data/lib/import/shake_grammar/lexer.rb +3 -0
  19. data/lib/import/shake_script.rb +7 -4
  20. data/lib/import/shake_text.rb +4 -4
  21. data/lib/import/syntheyes.rb +4 -4
  22. data/lib/pipeline/base.rb +19 -11
  23. data/lib/tracksperanto.rb +1 -1
  24. data/lib/tracksperanto/accumulator.rb +45 -19
  25. data/lib/tracksperanto/buffer_io.rb +3 -2
  26. data/lib/tracksperanto/const_name.rb +2 -0
  27. data/lib/tracksperanto/progressive_io.rb +3 -1
  28. data/lib/tracksperanto/tracker.rb +2 -1
  29. data/lib/tracksperanto/uv_coordinates.rb +3 -1
  30. data/lib/tracksperanto/zip_tuples.rb +2 -1
  31. data/test/helper.rb +0 -5
  32. data/test/import/samples/shake_script/shake_tracker_nodes.shk +11 -299
  33. data/test/import/test_3de_import.rb +2 -5
  34. data/test/import/test_3de_import3.rb +2 -2
  35. data/test/import/test_boujou_import.rb +2 -2
  36. data/test/import/test_flame_import.rb +9 -8
  37. data/test/import/test_match_mover_import.rb +2 -4
  38. data/test/import/test_maya_live_import.rb +5 -4
  39. data/test/import/test_nuke_import.rb +20 -16
  40. data/test/import/test_pftrack_import.rb +10 -8
  41. data/test/import/test_shake_script_import.rb +12 -22
  42. data/test/import/test_shake_text_import.rb +2 -2
  43. data/test/import/test_syntheyes_import.rb +7 -8
  44. data/test/test_accumulator.rb +31 -0
  45. data/test/test_cli.rb +2 -2
  46. metadata +18 -13
data/.gemtest ADDED
File without changes
data/DEVELOPER_DOCS.rdoc CHANGED
@@ -30,45 +30,47 @@ to write your own Pipeline class or reimplement parts of it.
30
30
  Almost every module in Tracksperanto has a method called report_progress. This method is used to notify an external callback of what you are doing, and helps keep
31
31
  the software user-friendly. A well-behaved Tracksperanto module should manage it's progress reports properly.
32
32
 
33
- === Sample script
34
-
35
- require "rubygems"
36
- require "tracksperanto"
37
-
38
- include Tracksperanto
39
-
40
- # Create the importer object
41
- some_importer = Importer.new(:width => 1024, :height => 576)
42
-
43
- # Some object responding to #push has to be the receiver
44
- # In this case we will use an array but this might get out of hand
45
- # if you have alot of trackers - Tracksperanto uses a disk-based
46
- # buffer for this instead (see Accumulator)
47
- some_importer.receiver = []
33
+ === Reusing components
48
34
 
49
- # Run the import with the importer
50
- some_importer.stream_parse((File.open("source_file.fmt")))
35
+ Tracksperanto contains some nice bits, such as a full grammar lexer for Shake scripts (Tracksperanto::ShakeGrammar::Lexer), a couple of handy buffering
36
+ classes (Tracksperanto::BufferIO and Tracksperanto::Accumulator) and a parser for any Flame setups containing channels (Tracksperanto::Import::FlameStabilizer).
37
+ Play responsibly.
51
38
 
52
- # Now the receiver contains trackers! Weeee!
53
- trackers = importer.receiver
54
-
55
- # Create the exporter and pass the output file to it
56
- some_exporter = Exporter.new(File.open("exported_file.other", "wb"))
57
-
58
- # Now add some middlewares, for example a Scale
59
- scaler = Middleware::Scaler.new(some_exporter, :x_factor => 2)
60
- # ... and a slip
61
- slipper = Middleware::Slipper.new(scaler, :offset => 2)
62
- # Middlewares wrap exporters and other middlewares, so you can chain them
63
- # ad nauseam
64
-
65
- # Now when we send export commands to the Slipper it will play them through
66
- # to the Scaler and the Scaler in turn will send commands to the exporter.
67
- slipper.start_export(1024, 576)
68
- trackers.each do | t |
69
- slipper.start_tracker_segment(t.name)
70
- t.each {|kf slipper.export_point(kf.frame, kf.abs_x, kf.abs_y, kf.residual) }
71
- slipper.end_tracker_segment
72
- end
39
+ === Sample script
73
40
 
74
- # And we are done!
41
+ require "rubygems"
42
+ require "tracksperanto"
43
+
44
+ include Tracksperanto
45
+
46
+ # Create the importer object, for example for a Shake script.
47
+ # get_importer will give you the good class even you get the capitalization
48
+ # wrong!
49
+ some_importer = Tracksperanto.get_importer("shakescript").new(:width => 1024, :height => 576)
50
+ some_importer.io = File.open("source_file.fmt")
51
+
52
+ # The importer responds to each() so if your file is not too big you can just load all the trackers
53
+ # as an array. If you expect to have alot of trackers investigate a way to buffer them on disk
54
+ # instead (see Accumulator)
55
+ trackers = some_importer.to_a
56
+
57
+ # Create the exporter and pass the output file to it
58
+ some_exporter = Tracksperanto.get_exporter("flamestabilizer").new(File.open("exported_file.other", "wb"))
59
+
60
+ # Now add some middlewares, for example a Scale
61
+ scaler = Middleware::Scaler.new(some_exporter, :x_factor => 2)
62
+ # ... and a slip
63
+ slipper = Middleware::Slipper.new(scaler, :offset => 2)
64
+ # Middlewares wrap exporters and other middlewares, so you can chain them
65
+ # ad nauseam
66
+
67
+ # Now when we send export commands to the Slipper it will play them through
68
+ # to the Scaler and the Scaler in turn will send commands to the exporter.
69
+ slipper.start_export(1024, 576)
70
+ trackers.each do | t |
71
+ slipper.start_tracker_segment(t.name)
72
+ t.each {|kf slipper.export_point(kf.frame, kf.abs_x, kf.abs_y, kf.residual) }
73
+ slipper.end_tracker_segment
74
+ end
75
+
76
+ # And we are done!
data/History.txt CHANGED
@@ -1,3 +1,10 @@
1
+ === 2.2.0 / 2011-03-01
2
+
3
+ * Improve documentation substantially
4
+ * Changed the Import::Base interface yo use enumeration instead of @receiver.
5
+ Upside: This allows us to convert importers to an array of trackers and other niceties.
6
+ Downside: stream_parse will be deprecated. It is however still available for backwards compatibility
7
+
1
8
  === 2.1.1 / 2011-02-14
2
9
 
3
10
  * Fix handling of Shake scripts containing stabilizer nodes with no animation
data/Manifest.txt CHANGED
@@ -2,7 +2,7 @@ DEVELOPER_DOCS.rdoc
2
2
  History.txt
3
3
  MIT_LICENSE.txt
4
4
  Manifest.txt
5
- README.txt
5
+ README.rdoc
6
6
  Rakefile
7
7
  bin/tracksperanto
8
8
  lib/export/base.rb
@@ -26,6 +26,7 @@ lib/import/equalizer4.rb
26
26
  lib/import/flame_stabilizer.rb
27
27
  lib/import/match_mover.rb
28
28
  lib/import/maya_live.rb
29
+ lib/import/nuke_grammar/utils.rb
29
30
  lib/import/nuke_script.rb
30
31
  lib/import/pftrack.rb
31
32
  lib/import/shake_grammar/catcher.rb
@@ -152,6 +153,7 @@ test/middleware/test_reformat_middleware.rb
152
153
  test/middleware/test_scaler_middleware.rb
153
154
  test/middleware/test_shift_middleware.rb
154
155
  test/middleware/test_slip_middleware.rb
156
+ test/test_accumulator.rb
155
157
  test/test_buffer_io.rb
156
158
  test/test_cli.rb
157
159
  test/test_const_name.rb
@@ -41,10 +41,6 @@ footage you are tracking came cropped or in a wrong aspect - the only way to sol
41
41
  will be to retrack it from scratch. Tracksperanto allows you to work around this
42
42
  by applying simple transformations to the tracks.
43
43
 
44
- == Licensing
45
-
46
- Tracksperanto is made avalable under the MIT license that is included in the package.
47
-
48
44
  == Usage
49
45
 
50
46
  The main way to use Tracksperanto is with the the supplied "tracksperanto" binary, like so:
@@ -69,7 +65,7 @@ Import and export support:
69
65
  * Syntheyes 2D tracking data exports
70
66
  * 3DE point exports (as output by the default script) - versions 3 and 4
71
67
  * MatchMover Pro .rz2
72
- * MayaLive track export (square pixel aspect only, you will need to write some extra code to convert that)
68
+ * MayaLive track export (square pixel aspect only, you will need to write some extra code if your tracks are based on nonsquare pixels)
73
69
  * Flame .stabilizer file
74
70
  * Boujou feature track export
75
71
 
@@ -79,19 +75,21 @@ Import only:
79
75
  == Modularity
80
76
 
81
77
  Tracksperanto is very modular and can process data passing through it (like
82
- scaling a proxy track up). Internally, Tracksperanto talks Exporters, Importers and
83
- Middlewares. Any processing chain (called a Pipeline) usually works like this:
78
+ scaling a proxy track up). Consult the --help option to see what is available.
84
79
 
85
- * Tracker file is read and trackers and their
86
- keyframes are extracted, converting them to
87
- the internal representation.
88
- * Trackers and their keyframes are dumped to all export
89
- formats Tracksperanto supports, optionally passing through Middleware
80
+ == Development
90
81
 
82
+ If you are interested in reusing Tracksperanto's code or adding modules to the software consult
83
+ the {short developer introduction}[DEVELOPER_DOCS.rdoc]
91
84
 
92
85
  == Limitations
93
86
 
94
87
  Information about the search area, reference area and offset is not passed along (outside
95
88
  of scope for the app and different trackers handle these differently, if at all). For some
96
89
  modules no residual will be passed along (3D tracking apps generally do not export residual
97
- with backprojected 3D features).
90
+ with backprojected 3D features).
91
+
92
+
93
+ == Licensing
94
+
95
+ Tracksperanto is made avalable under the MIT license that is included in the package.
data/Rakefile CHANGED
@@ -8,12 +8,14 @@ begin
8
8
  (Hoe::RUBY_DEBUG ? " #{RUBY_DEBUG}" : '')
9
9
 
10
10
  Hoe.spec('tracksperanto') do | p |
11
+ p.readme_file = 'README.rdoc'
12
+ p.extra_rdoc_files = FileList['*.rdoc']
11
13
  p.version = Tracksperanto::VERSION
14
+
12
15
  p.extra_deps = {"progressbar" => ">=0"}
13
16
  p.extra_dev_deps = {"flexmock" => ">=0"}
14
17
  p.rubyforge_name = 'guerilla-di'
15
18
  p.developer('Julik Tarkhanov', 'me@julik.nl')
16
- p.extra_rdoc_files = p.extra_rdoc_files.reject{|e| e =~ "samples\/"}
17
19
  p.clean_globs = %w( **/.DS_Store coverage.info **/*.rbc .idea)
18
20
  end
19
21
  rescue LoadError
@@ -1,6 +1,7 @@
1
1
  # Export each tracker as a single Tracker3 node
2
2
  class Tracksperanto::Export::NukeScript < Tracksperanto::Export::Base
3
- #:nodoc:
3
+
4
+ #:nodoc
4
5
 
5
6
  NODE_TEMPLATE = %[
6
7
  Tracker3 {
@@ -27,7 +28,7 @@ Constant {
27
28
  xpos 0
28
29
  ypos -60
29
30
  }]
30
- #:doc:
31
+ #:doc
31
32
 
32
33
  # Offset by which the new nodes will be shifted down in the node graph
33
34
  SCHEMATIC_OFFSET = 30
data/lib/import/base.rb CHANGED
@@ -1,16 +1,18 @@
1
- # The base class for all the import modules. By default, when you inherit from this class the inherited class will be included
2
- # in the list of supported Tracksperanto importers. The API that an importer should present is very basic, and consists only of a few methods.
3
- # The main method is parse(io) which should return an array of Tracker objects.
1
+ # The base class for all the import modules. By default, when you inherit from
2
+ # this class the inherited class will be included in the list of supported
3
+ # Tracksperanto importers. The API that an importer should present is very
4
+ # basic, and consists only of a few methods. The main method is
5
+ # stream_parse(io)
4
6
  class Tracksperanto::Import::Base
7
+ include Enumerable
5
8
  include Tracksperanto::Safety
6
9
  include Tracksperanto::Casts
7
10
  include Tracksperanto::BlockInit
8
11
  include Tracksperanto::ZipTuples
9
12
  include Tracksperanto::ConstName
10
13
 
11
- # Every time the importer accumulates a tracker this object's #push method will be called.
12
- # Can be an array or a more full-featured buffer
13
- attr_accessor :receiver
14
+ # Handle to the IO with data being parsed
15
+ attr_accessor :io
14
16
 
15
17
  # Tracksperanto will assign a proc that reports the status of the import to the caller.
16
18
  # This block is automatically used by report_progress IF the proc is assigned. Should
@@ -18,17 +20,14 @@ class Tracksperanto::Import::Base
18
20
  # yourself)
19
21
  attr_accessor :progress_block
20
22
 
21
- # The original width of the tracked image.
23
+ # The original width and height of the tracked image.
22
24
  # If you need to know the width for your specific format and cannot autodetect it,
23
25
  # Trakcksperanto will assign the passed width and height to the importer object before running
24
26
  # the import. If not, you can replace the assigned values with your own. At the end of the import
25
27
  # procedure, Tracksperanto will read the values from you again and will use the read values
26
28
  # for determining the original comp size. +width+ and +height+ MUST return integer values after
27
29
  # the import completes
28
- attr_accessor :width
29
-
30
- # The original height of the comp, same conventions as for width apply
31
- attr_accessor :height
30
+ attr_accessor :width, :height
32
31
 
33
32
  # These reader methods will raise when the values are nil
34
33
  cast_to_int :width, :height
@@ -41,6 +40,9 @@ class Tracksperanto::Import::Base
41
40
  super
42
41
  end
43
42
 
43
+ # OBSOLETE, do not use
44
+ attr_accessor :receiver
45
+
44
46
  # Return an extension WITH DOT if this format has a typical extension that
45
47
  # you can detect (like ".nk" for Nuke)
46
48
  def self.distinct_file_ext
@@ -64,28 +66,15 @@ class Tracksperanto::Import::Base
64
66
  @progress_block.call(message) if @progress_block
65
67
  end
66
68
 
67
- # OBSOLETE: do not implement this method in your importer. This is used to accumulate trackers in an array
68
- # and then send it to the caller. Used in tests.
69
- def parse(track_file_io)
70
- @receiver = []
71
- stream_parse(track_file_io)
72
- @receiver
73
- end
74
-
75
- # The main method of the parser. Will receive an IO handle to the file being imported, and should
76
- # send each consecutive tracker via the send_tracker method.
77
- # Note that in general it's a good idea to stream-parse a document
78
- # instead of bulk-reading it into memory (since Tracksperanto tries to be mem-efficient when dealing
79
- # with large files)
80
- def stream_parse(track_file_io)
69
+ # The main method of the parser. Should
70
+ # yield each tracker that has been fully parsed. After calling this method the caller can ask for
71
+ # width and height as well.
72
+ def each
81
73
  end
82
74
 
83
- # When a tracker has been detected completely (all keyframes) call this method with the tracker object as argument
75
+ # OBSOLETE: do not use
84
76
  def send_tracker(tracker_obj)
85
- if @receiver
86
- @receiver.push(tracker_obj)
87
- else
88
- raise "Tracker received but no @receiver has been set for #{self.inspect}"
89
- end
77
+ STDERR.puts "Import::Base#send_tracker has been deprecated, please rewrite your importer to use yield(t) inside each instead"
78
+ @receiver.push(tracker_obj)
90
79
  end
91
80
  end
data/lib/import/boujou.rb CHANGED
@@ -4,13 +4,13 @@ class Tracksperanto::Import::Boujou < Tracksperanto::Import::Base
4
4
  "Boujou feature tracks export"
5
5
  end
6
6
 
7
- def stream_parse(io)
8
- wrapped_io = Tracksperanto::ExtIO.new(io)
7
+ def each
8
+ wrapped_io = Tracksperanto::ExtIO.new(@io)
9
9
  detect_columns(wrapped_io)
10
10
  trackers = {}
11
11
  filtering_trackers_from(wrapped_io) do | name, frame, x, y |
12
12
  if @last_tracker && (name != @last_tracker.name)
13
- send_tracker(@last_tracker) if @last_tracker && @last_tracker.any?
13
+ yield(@last_tracker) if @last_tracker && @last_tracker.any?
14
14
  @last_tracker = nil
15
15
  end
16
16
 
@@ -22,7 +22,7 @@ class Tracksperanto::Import::Boujou < Tracksperanto::Import::Base
22
22
  @last_tracker.keyframe!(:frame => (frame.to_i - 1), :abs_y => (@height.to_f - y.to_f), :abs_x => x)
23
23
  end
24
24
 
25
- send_tracker(@last_tracker) if @last_tracker && @last_tracker.any?
25
+ yield(@last_tracker) if @last_tracker && @last_tracker.any?
26
26
  end
27
27
 
28
28
  private
@@ -9,10 +9,10 @@ class Tracksperanto::Import::Equalizer3 < Tracksperanto::Import::Base
9
9
  true
10
10
  end
11
11
 
12
- def stream_parse(passed_io)
13
- io = Tracksperanto::ExtIO.new(passed_io)
12
+ def each
13
+ io = Tracksperanto::ExtIO.new(@io)
14
14
  detect_format!(io)
15
- extract_trackers(io)
15
+ extract_trackers(io) {|t| yield(t) }
16
16
  end
17
17
 
18
18
  private
@@ -25,7 +25,7 @@ class Tracksperanto::Import::Equalizer3 < Tracksperanto::Import::Base
25
25
  def extract_trackers(io)
26
26
  while line = io.gets do
27
27
  if line =~ /^(\w+)/ # Tracker name
28
- send_tracker(@last_tracker) if @last_tracker && @last_tracker.any?
28
+ yield(@last_tracker) if @last_tracker && @last_tracker.any?
29
29
  @last_tracker = Tracksperanto::Tracker.new(:name => line.strip)
30
30
  report_progress("Capturing tracker #{line.strip}")
31
31
  elsif line =~ /^\t/
@@ -33,7 +33,7 @@ class Tracksperanto::Import::Equalizer3 < Tracksperanto::Import::Base
33
33
  end
34
34
  end
35
35
 
36
- send_tracker(@last_tracker) if @last_tracker && @last_tracker.any?
36
+ yield(@last_tracker) if @last_tracker && @last_tracker.any?
37
37
  end
38
38
 
39
39
  def make_keyframe(from_line)
@@ -5,11 +5,10 @@ class Tracksperanto::Import::Equalizer4 < Tracksperanto::Import::Base
5
5
  "3DE v4 point export file"
6
6
  end
7
7
 
8
-
9
- def stream_parse(passed_io)
10
- io = Tracksperanto::ExtIO.new(passed_io)
8
+ def each
9
+ io = Tracksperanto::ExtIO.new(@io)
11
10
  num_t = detect_num_of_points(io)
12
- num_t.times { send_tracker(extract_tracker(io)) }
11
+ num_t.times { yield(extract_tracker(io)) }
13
12
  end
14
13
 
15
14
  private
@@ -71,17 +71,17 @@ class Tracksperanto::Import::FlameStabilizer < Tracksperanto::Import::Base
71
71
  private :to_ary
72
72
  end
73
73
 
74
- def stream_parse(io)
74
+ def each
75
75
  report_progress("Extracting setup size")
76
- self.width, self.height = extract_width_and_height_from_stream(io)
76
+ self.width, self.height = extract_width_and_height_from_stream(@io)
77
77
  report_progress("Extracting all animation channels")
78
- channels = extract_channels_from_stream(io)
78
+ channels = extract_channels_from_stream(@io)
79
79
 
80
80
  raise "The setup contained no channels that we could process" if channels.empty?
81
81
  raise "A channel was nil" if channels.find{|e| e.nil? }
82
82
 
83
83
  report_progress("Assembling tracker curves from channels")
84
- scavenge_trackers_from_channels(channels) {|t| send_tracker(t) }
84
+ scavenge_trackers_from_channels(channels) {|t| yield(t) }
85
85
  end
86
86
 
87
87
  private
@@ -185,12 +185,8 @@ Channel tracker1/ref/x
185
185
  shift_tuples = zip_curve_tuples(shift_x, shift_y)
186
186
  track_tuples = zip_curve_tuples(track_x, track_y)
187
187
 
188
- base_x, base_y = begin
189
- report_progress("Detecting base value")
190
- find_base_x_and_y(track_tuples, shift_tuples)
191
- rescue UseBase
192
- [track_x.base_value, track_y.base_value]
193
- end
188
+ report_progress("Detecting base value")
189
+ base_x, base_y = find_base_x_and_y(track_tuples, shift_tuples)
194
190
 
195
191
  total_kf = 1
196
192
  t.keyframes = shift_tuples.map do | (at, x, y) |
@@ -205,18 +201,10 @@ Channel tracker1/ref/x
205
201
  return t
206
202
  end
207
203
 
208
- UseBase = RuntimeError
209
-
210
204
  def find_base_x_and_y(track_tuples, shift_tuples)
211
205
  base_track_tuple = track_tuples.find do | track_tuple |
212
206
  shift_tuples.find { |shift_tuple| shift_tuple[0] == track_tuple [0] }
213
- end
214
- if base_track_tuple
215
- base_track_tuple[1..2]
216
- elsif track_tuples[0]
217
- track_tuples[0][1..2]
218
- else
219
- raise UseBase
220
- end
207
+ end || track_tuples[0]
208
+ base_track_tuple[1..2]
221
209
  end
222
210
  end
@@ -12,10 +12,9 @@ class Tracksperanto::Import::MatchMover < Tracksperanto::Import::Base
12
12
  ".rz2"
13
13
  end
14
14
 
15
- def stream_parse(io)
16
- trackers = []
17
- detect_format(io)
18
- extract_trackers(io) { |t| send_tracker(t) }
15
+ def each
16
+ detect_format(@io)
17
+ extract_trackers(@io) { |t| yield(t) }
19
18
  end
20
19
 
21
20
  private