tracksperanto 1.6.4 → 1.6.5

Sign up to get free protection for your applications and to get access to all the features.
data/.DS_Store CHANGED
Binary file
data/History.txt CHANGED
@@ -1,3 +1,8 @@
1
+ === 1.6.5 / 2009-11-27
2
+
3
+ * Adds the --only option for the tracksperanto binary to only export a specific format
4
+ * Automatically unlink tempfiles in the Equalizer4 exporter
5
+
1
6
  === 1.6.4 / 2009-11-25
2
7
 
3
8
  * Adds Boujou 2d feature import support (to export for Boujou use the Shake text format)
data/README.txt CHANGED
@@ -19,72 +19,62 @@ at once. When doing tracks of long shots at high resolutions (like 2K and HD), e
19
19
  on 32bit platforms, the app usually cannot even cache the whole shot and tracking is very
20
20
  very slow.
21
21
 
22
- Compositing apps, in contrast, are very efficient in this. Both Shake and Nuke offer very
23
- fast trackers because they can load only the search area for the tracker into memory and
24
- not a pixel more. When you use manual feature selection you can create many tracks very
25
- quickyl even without having fast IO. Flame is also very fast since it has virtually zero IO
26
- overhead thanks to it's fast storage. Compositing apps also allow for precise, local
27
- preprocessing of tracking features like boosting contrast, doing expensive (especially
28
- temporal) denoise, blurs and so on, while matchmoving apps offer only a single, global
29
- preprocessing step (like a LUT or a gamma curve adjustment) which is not adequate for all
30
- of the features being tracked.
31
-
32
- It's thusly very natural to track in a modern compositing app that has selective image
22
+ Compositing apps, in contrast, are very efficient. Both Shake and Nuke offer very
23
+ fast trackers because they have tiling image engines and can load only the search area
24
+ for the tracker into memory and not a pixel more. When you use manual feature selection
25
+ you can create many tracks quickly even without having fast IO. Flame is also very fast
26
+ since it has virtually zero IO overhead thanks to it's fast storage. Compositing apps
27
+ also allow for precise, local preprocessing of tracking features like boosting contrast,
28
+ doing expensive (especially temporal) denoise, blurs and so on, while matchmoving apps
29
+ offer only a single, global preprocessing step (like a LUT or a gamma curve adjustment)
30
+ which is not adequate for all of the features being tracked.
31
+
32
+ So it's very natural to track in a modern compositing app that has selective image
33
33
  loading, and then export one single group of tracks into all of the matchmoving
34
- applications and figuring out which one gives a better camera solve. Also, you can always
35
- escape into the 2D world if no 3D app proves to be adequate. If you need to move from one
36
- app to another, you won't have to retrack.
34
+ applications at once. Also, you can always escape into the 2D world if no 3D app proves
35
+ to be adequate. If you need to move from one app to another, you won't have to retrack.
37
36
 
38
37
  Another issue with tracks is adjusting to formats. Very few apps allow you to convert your
39
38
  tracks in one stop from format to format - like doing an unproportional scale on the
40
- tracks, or moving them a few pixels left and right. This comes at a high cost of the
39
+ tracks, or moving them a few pixels left and right. This comes at a high cost if the
41
40
  footage you are tracking came cropped or in a wrong aspect - the only way to solve the shot
42
41
  will be to retrack it from scratch. Tracksperanto allows you to work around this
43
42
  by applying simple transformations to the tracks.
44
43
 
45
44
  == Usage
46
45
 
47
- The main way to use Tracksperanto is to use the supplied "tracksperanto" binary, like so:
46
+ The main way to use Tracksperanto is with the the supplied "tracksperanto" binary, like so:
48
47
 
49
48
  tracksperanto -w 1920 -h 1080 /Films/Blockbuster/Shots/001/script.shk
50
49
 
51
50
  -w and -h stand for Width and Height and define the size of your comp (different tracking
52
51
  apps use different coordinate systems and we need to know the size of the comp to properly
53
- convert these). You also have additional options like -xs, -ys and --slip - consult the
54
- usage info for the tracksperanto binary.
52
+ convert these). Some formats contain clear hints on the size of the comp, but most don't -
53
+ for formats that do contain them you don't need to supply anything.
54
+ You also have additional options like -xs, -ys and --slip - consult the usage info for the tracksperanto binary.
55
55
 
56
56
  The converted files will be saved in the same directory as the source, if resulting
57
57
  converted files already exist <b>they will be overwritten without warning</b>.
58
58
 
59
59
  == Format support
60
60
 
61
- Import support:
62
-
63
- * Flame .stabilizer file (not the .stabilizer.p blob format)
64
- * Nuke script (Tracker3 nodes, also known as Tracker)
65
- * Shake script (Tracker, Matchmove and Stabilize nodes)
61
+ Import and export support:
62
+ * Nuke v5 script (Tracker3 nodes, also known as Tracker in the UI - this is the node that you track with)
66
63
  * Shake tracker node export (textfile with many tracks per file)
67
- * PFTrack 2dt files
64
+ * PFTrack 2dt files (version 4 and 5)
68
65
  * Syntheyes 2D tracking data exports
69
66
  * 3DE point exports (as output by the default script) - versions 3 and 4
70
67
  * MatchMover Pro .rz2
71
68
  * MayaLive track export (square pixel aspect only)
72
69
 
73
- Export support:
74
-
75
- * Shake text file (many trackers per file), also accepted by Boujou.
76
- May crash Shake with more than 4-5 tracks.
77
- * PFTrack 2dt file (with residuals)
78
- * Syntheyes 2D tracking data import (UV coordinates)
79
- * Nuke script
80
- * 3DE point exports (as accepted by the default import)
81
- * MatchMover Pro .rz2
82
- * MayaLive track export (square pixel aspect only)
70
+ Import only:
71
+ * Boujou feature track export
72
+ * Flame .stabilizer file (not the .stabilizer.p blob format)
73
+ * Shake script (Tracker, Matchmove and Stabilize nodes)
83
74
 
84
75
  == Modularity
85
76
 
86
- Tracksperanto supports many export and import formats. It also can help when you need to
87
- import and export the same format, but you need some operation applied to the result (like
77
+ Tracksperanto is very modular and can process data passing through it (like
88
78
  scaling a proxy track up). Internally, Tracksperanto talks Exporters, Importers and
89
79
  Middlewares. Any processing chain (called a Pipeline) usually works like this:
90
80
 
data/bin/tracksperanto CHANGED
@@ -26,8 +26,10 @@ golden_tracks = false
26
26
  x_shift = 0
27
27
  y_shift = 0
28
28
  set_prefix = ''
29
-
29
+ sole_format = nil
30
+ reader_name = "ShakeScript"
30
31
  readers = Tracksperanto.importer_names
32
+ writers = Tracksperanto.exporter_names
31
33
 
32
34
  parser = OptionParser.new do | p |
33
35
  p.banner = "Usage: tracksperanto -f ShakeScript -w 1920 -h 1080 /Films/Blockbuster/Shots/001/script.shk"
@@ -36,15 +38,9 @@ parser = OptionParser.new do | p |
36
38
  }
37
39
  p.on(" -f", "--from TRANSLATOR", String,
38
40
  "Use the specific import translator (will try to autodetect, but can be #{Tracksperanto.importer_names.join(', ')})") do | f |
39
- begin
40
- reader_klass = Tracksperanto::Import.const_get(f)
41
- rescue NameError => e
42
- reader_list = readers.join("\n\t")
43
- STDERR.puts "Unknown reader #{f.inspect}, available readers:\n\t#{readers.join(', ')}"
44
- exit(-1)
45
- end
41
+ reader_name = f
46
42
  end
47
- p.on(" -p", "--prefix PREFIX", String, "A prefix to prepend to tracker names in bluk") { |w| set_prefix = w }
43
+ p.on(" -p", "--prefix PREFIX", String, "A prefix to prepend to tracker names in bulk") { |w| set_prefix = w }
48
44
  p.on(" -w", "--width WIDTH_IN_PIXELS", Integer, "Absolute input comp width in pixels (will try to autodetect)") { |w| width = w }
49
45
  p.on(" -h", "--height HEIGHT_IN_PIXELS", Integer, "Absolute input comp height in pixels (will try to autodetect)") {|w| height = w }
50
46
  p.on(" -xs", "--xscale X_SCALING_FACTOR", Float, "Scale the result in X by this factor (1.0 is the default)") {|sx| scale_x = sx }
@@ -59,6 +55,9 @@ parser = OptionParser.new do | p |
59
55
  p.on(" -ry", "--reformat-y NEW_PIX_HEIGHT", Integer, "Reformat the comp to this height and scale all tracks to it") {|rh|
60
56
  reformat_h = rh
61
57
  }
58
+ p.on(" -o", "--only EXPORTER_NAME", String, "Only export the selected format, format must be one of #{writers.join(", ")}") {|f|
59
+ sole_format = f
60
+ }
62
61
  p.on(" -xm", "--xshift X_IN_PIXELS", Float, "Move the points left or right") {|sx| x_shift = sx }
63
62
  p.on(" -ym", "--yshift Y_IN_PIXELS", Float, "Move the points up or down") {|sx| y_shift = sx }
64
63
  p.on("--version", "Show the version and exit") {|v|
@@ -75,6 +74,13 @@ rescue OptionParser::MissingArgument => e
75
74
  exit(-1)
76
75
  end
77
76
 
77
+ begin
78
+ reader_klass = Tracksperanto::Import.const_get(reader_name)
79
+ rescue NameError => e
80
+ STDERR.puts "Unknown reader #{reader_name}, available readers: #{readers.join(', ')}"
81
+ exit(-1)
82
+ end
83
+
78
84
  input_file = ARGV.pop
79
85
  if !input_file
80
86
  STDERR.puts "No input file provided - should be the last argument"
@@ -84,6 +90,15 @@ end
84
90
 
85
91
  pipe = Tracksperanto::Pipeline::Base.new
86
92
  pipe.progress_block = lambda{|percent, msg| STDOUT.write(".") }
93
+ if sole_format
94
+ begin
95
+ pipe.exporters = [Tracksperanto::Export.const_get(sole_format)]
96
+ rescue NameError
97
+ STDERR.puts "Unknown exporter #{sole_format}. Available exporters: #{writers.join(", ")}"
98
+ exit(-1)
99
+ end
100
+ end
101
+
87
102
  pipe.run(input_file, :pix_w => width, :pix_h => height, :parser => reader_klass) do | scaler, slipper, golden, reformat, shift, prefix |
88
103
  slipper.slip = slip
89
104
  scaler.x_factor = scale_x
@@ -31,7 +31,7 @@ class Tracksperanto::Export::Equalizer4 < Tracksperanto::Export::Base
31
31
  @internal_io.puts("0") # Color of the point, 0 is red
32
32
  @internal_io.puts(@num_of_kfs)
33
33
  @internal_io.puts(@tracker_buffer.read)
34
- @tracker_buffer.close
34
+ @tracker_buffer.close!
35
35
  end
36
36
 
37
37
  def end_export
data/lib/import/boujou.rb CHANGED
@@ -8,8 +8,7 @@ class Tracksperanto::Import::Boujou < Tracksperanto::Import::Base
8
8
  wrapped_io = Tracksperanto::ExtIO.new(io)
9
9
  detect_columns(wrapped_io)
10
10
  trackers = {}
11
- extract_trackers(wrapped_io) do | k |
12
- name, frame, x, y = k["track_id"], k["view"], k["x"], k["y"]
11
+ filtering_trackers_from(wrapped_io) do | name, frame, x, y |
13
12
  trackers[name] ||= Tracksperanto::Tracker.new(:name => name)
14
13
  report_progress("Extracting frame #{frame} of #{name}")
15
14
  trackers[name].keyframe!(:frame => (frame.to_i - 1), :abs_y => (@height.to_f - y.to_f), :abs_x => x)
@@ -39,11 +38,12 @@ class Tracksperanto::Import::Boujou < Tracksperanto::Import::Base
39
38
  #
40
39
  # # track_id view x y
41
40
  # Target_track_1 5 252.046 171.677
42
- def extract_trackers(io)
41
+ def filtering_trackers_from(io)
43
42
  until io.eof?
44
43
  line = io.gets_and_strip
45
44
  next if comment?(line)
46
- yield(make_column_hash(line))
45
+ column = make_column_hash(line)
46
+ yield(column["track_id"], column["view"], column["x"], column["y"])
47
47
  end
48
48
  end
49
49
 
@@ -70,7 +70,9 @@ class Tracksperanto::Import::FlameStabilizer < Tracksperanto::Import::Base
70
70
  end
71
71
 
72
72
  def parse(io)
73
+ report_progress("Extracting setup size")
73
74
  self.width, self.height = extract_width_and_height_from_stream(io)
75
+ report_progress("Extracting all animation channels")
74
76
  channels = extract_channels_from_stream(io)
75
77
 
76
78
  raise "The setup contained no channels that we could process" if channels.empty?
@@ -140,6 +142,7 @@ Channel tracker1/ref/x
140
142
  until io.eof?
141
143
  line = io.gets
142
144
  if line =~ channel_matcher
145
+ report_progress("Extracting channel #{$1}")
143
146
  channels << extract_channel_from(io, $1)
144
147
  end
145
148
  end
@@ -155,6 +158,7 @@ Channel tracker1/ref/x
155
158
  def scavenge_trackers_from_channels(channels)
156
159
  trackers = []
157
160
  channels.select{|e| e.name =~ /\/#{REF_CHANNEL}\/x/}.each do | track_x |
161
+ report_progress("Detected reference channel #{track_x}")
158
162
  trackers << grab_tracker(channels, track_x)
159
163
  end
160
164
 
@@ -174,6 +178,7 @@ Channel tracker1/ref/x
174
178
  track_tuples = zip_curve_tuples(track_x, track_y)
175
179
 
176
180
  base_x, base_y = begin
181
+ report_progress("Detecting base value")
177
182
  find_base_x_and_y(track_tuples, shift_tuples)
178
183
  rescue UseBase
179
184
  [track_x.base_value, track_y.base_value]
@@ -37,6 +37,7 @@ class Tracksperanto::Import::NukeScript < Tracksperanto::Import::Base
37
37
  elsif line =~ NODENAME
38
38
  tracks_in_tracker.each_with_index do | t, i |
39
39
  t.name = "#{$1}_track#{i+1}"
40
+ report_progress("Scavenging Tracker3 node #{t.name}")
40
41
  end
41
42
  return tracks_in_tracker
42
43
  end
@@ -50,21 +51,23 @@ class Tracksperanto::Import::NukeScript < Tracksperanto::Import::Base
50
51
  zip_curve_tuples(x_curve, y_curve)
51
52
  end
52
53
 
53
- # Scan a curve to a number of triplets
54
+ SECTION_START = /^x(\d+)$/
55
+ KEYFRAME = /^([-\d\.]+)$/
56
+
57
+ # Scan a curve to a number of tuples of [frame, value]
54
58
  def parse_curve(curve_text)
55
59
  # Replace the closing curly brace with a curly brace with space so that it gets caught by split
56
60
  atoms, tuples = curve_text.gsub(/\}/m, ' }').split, []
57
61
  # Nuke saves curves very efficiently. x(keyframe_number) means that an uninterrupted sequence of values will start,
58
62
  # after which values follow. When the curve is interrupted in some way a new x(keyframe_number) will signifu that we
59
63
  # skip to that specified keyframe and the curve continues from there
60
- section_start = /^x(\d+)$/
61
- keyframe = /^([-\d\.]+)$/
62
64
 
63
65
  last_processed_keyframe = 1
64
66
  while atom = atoms.shift
65
- if atom =~ section_start
67
+ if atom =~ SECTION_START
66
68
  last_processed_keyframe = $1.to_i
67
- elsif atom =~ keyframe
69
+ elsif atom =~ KEYFRAME
70
+ report_progress("Reading curve at frame #{last_processed_keyframe}")
68
71
  tuples << [last_processed_keyframe, $1.to_f]
69
72
  last_processed_keyframe += 1
70
73
  elsif atom == '}'
@@ -36,7 +36,7 @@ class Tracksperanto::Import::PFTrack < Tracksperanto::Import::Base
36
36
 
37
37
  num_of_keyframes = first_tracker_line.to_i
38
38
  t.keyframes = (1..num_of_keyframes).map do | keyframe_idx |
39
- report_progress("Reading keyframe #{keyframe_idx} of #{num_of_keyframes}")
39
+ report_progress("Reading keyframe #{keyframe_idx} of #{num_of_keyframes} in #{t.name}")
40
40
  Tracksperanto::Keyframe.new do |k|
41
41
  k.frame, k.abs_x, k.abs_y, k.residual = io.gets.chomp.split
42
42
  end
data/lib/tracksperanto.rb CHANGED
@@ -4,7 +4,7 @@ require 'tempfile'
4
4
 
5
5
  module Tracksperanto
6
6
  PATH = File.expand_path(File.dirname(__FILE__))
7
- VERSION = '1.6.4'
7
+ VERSION = '1.6.5'
8
8
 
9
9
  module Import; end
10
10
  module Export; end
@@ -6,16 +6,16 @@ module Tracksperanto::ZipTuples
6
6
  #
7
7
  # zip_curve_tuples( [[0, 12], [1, 23]], [[1, 12]]) #=> [[1, 23, 12]]
8
8
  #
9
+ # We make use of the fact that setting an offset index in an array fills it with nils up to
10
+ # the index inserted
9
11
  def zip_curve_tuples(*curves)
10
- tuples = []
11
-
12
- curves.each do | curve |
13
- curve.each do | keyframe |
14
- frame, value = keyframe
15
- tuples[frame] ? tuples[frame].push(value) : (tuples[frame] = [frame, value])
12
+ tuples = curves.inject([]) do | tuples, curve_of_at_and_value |
13
+ curve_of_at_and_value.each do | frame, value |
14
+ tuples[frame] = tuples[frame] ? (tuples[frame] << value) : [frame, value]
16
15
  end
16
+ tuples
17
17
  end
18
-
19
- tuples.compact.reject{|e| e.length < (curves.length + 1) }
18
+
19
+ tuples.reject{|e| e.nil? || (e.length < (curves.length + 1)) }
20
20
  end
21
- end
21
+ end
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tracksperanto
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.6.4
4
+ version: 1.6.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Julik Tarkhanov
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-11-26 00:00:00 +01:00
12
+ date: 2009-11-28 00:00:00 +01:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency