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 +0 -0
- data/History.txt +5 -0
- data/README.txt +26 -36
- data/bin/tracksperanto +24 -9
- data/lib/export/equalizer4.rb +1 -1
- data/lib/import/boujou.rb +4 -4
- data/lib/import/flame_stabilizer.rb +5 -0
- data/lib/import/nuke_script.rb +8 -5
- data/lib/import/pftrack.rb +1 -1
- data/lib/tracksperanto.rb +1 -1
- data/lib/tracksperanto/zip_tuples.rb +9 -9
- data/test/import/.DS_Store +0 -0
- metadata +2 -2
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
|
23
|
-
fast trackers because they can load only the search area
|
24
|
-
not a pixel more. When you use manual feature selection
|
25
|
-
|
26
|
-
overhead thanks to it's fast storage. Compositing apps
|
27
|
-
preprocessing of tracking features like boosting contrast,
|
28
|
-
temporal) denoise, blurs and so on, while matchmoving apps
|
29
|
-
preprocessing step (like a LUT or a gamma curve adjustment)
|
30
|
-
of the features being tracked.
|
31
|
-
|
32
|
-
|
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
|
35
|
-
|
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
|
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
|
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).
|
54
|
-
|
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
|
-
|
74
|
-
|
75
|
-
*
|
76
|
-
|
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
|
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
|
-
|
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
|
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
|
data/lib/export/equalizer4.rb
CHANGED
@@ -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
|
-
|
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
|
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
|
-
|
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]
|
data/lib/import/nuke_script.rb
CHANGED
@@ -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
|
-
|
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 =~
|
67
|
+
if atom =~ SECTION_START
|
66
68
|
last_processed_keyframe = $1.to_i
|
67
|
-
elsif atom =~
|
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 == '}'
|
data/lib/import/pftrack.rb
CHANGED
@@ -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
@@ -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
|
-
|
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.
|
18
|
+
|
19
|
+
tuples.reject{|e| e.nil? || (e.length < (curves.length + 1)) }
|
20
20
|
end
|
21
|
-
end
|
21
|
+
end
|
data/test/import/.DS_Store
CHANGED
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
|
+
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-
|
12
|
+
date: 2009-11-28 00:00:00 +01:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|