tracksperanto 1.6.4 → 1.6.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|