tracksperanto 1.0.0
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/Manifest.txt +37 -0
- data/README.txt +56 -0
- data/Rakefile +13 -0
- data/bin/tracksperanto +74 -0
- data/lib/export/base.rb +35 -0
- data/lib/export/flame_stabilizer.rb +50 -0
- data/lib/export/mux.rb +33 -0
- data/lib/export/pftrack.rb +30 -0
- data/lib/export/shake_text.rb +29 -0
- data/lib/export/syntheyes.rb +32 -0
- data/lib/import/base.rb +24 -0
- data/lib/import/flame_stabilizer.rb +34 -0
- data/lib/import/shake_script.rb +127 -0
- data/lib/import/shake_text.rb +29 -0
- data/lib/import/syntheyes.rb +32 -0
- data/lib/middleware/base.rb +28 -0
- data/lib/middleware/scaler.rb +24 -0
- data/lib/middleware/slipper.rb +12 -0
- data/lib/pipeline.rb +54 -0
- data/lib/tracksperanto.rb +131 -0
- data/test/.DS_Store +0 -0
- data/test/helper.rb +5 -0
- data/test/samples/.DS_Store +0 -0
- data/test/samples/flyover2DP_syntheyes.txt +12687 -0
- data/test/samples/megaTrack.action.3dtrack.stabilizer +29793 -0
- data/test/samples/one_shake_tracker.txt +49 -0
- data/test/samples/one_shake_tracker_from_first.txt +188 -0
- data/test/samples/shake_tracker_nodes.shk +921 -0
- data/test/samples/shake_tracker_nodes_to_syntheyes.txt +4091 -0
- data/test/samples/three_tracks_in_one_stabilizer.shk +320 -0
- data/test/samples/two_shake_trackers.txt +78 -0
- data/test/samples/two_tracks_in_one_tracker.shk +319 -0
- data/test/test_flame_block.rb +19 -0
- data/test/test_keyframe.rb +32 -0
- data/test/test_shake_export.rb +58 -0
- data/test/test_shake_script_import.rb +50 -0
- data/test/test_shake_text_import.rb +44 -0
- data/test/test_syntheyes_import.rb +25 -0
- metadata +111 -0
data/Manifest.txt
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
Manifest.txt
|
2
|
+
README.txt
|
3
|
+
Rakefile
|
4
|
+
bin/tracksperanto
|
5
|
+
lib/export/base.rb
|
6
|
+
lib/export/flame_stabilizer.rb
|
7
|
+
lib/export/mux.rb
|
8
|
+
lib/export/pftrack.rb
|
9
|
+
lib/export/shake_text.rb
|
10
|
+
lib/export/syntheyes.rb
|
11
|
+
lib/import/base.rb
|
12
|
+
lib/import/flame_stabilizer.rb
|
13
|
+
lib/import/shake_script.rb
|
14
|
+
lib/import/shake_text.rb
|
15
|
+
lib/import/syntheyes.rb
|
16
|
+
lib/middleware/base.rb
|
17
|
+
lib/middleware/scaler.rb
|
18
|
+
lib/middleware/slipper.rb
|
19
|
+
lib/pipeline.rb
|
20
|
+
lib/tracksperanto.rb
|
21
|
+
test/.DS_Store
|
22
|
+
test/helper.rb
|
23
|
+
test/samples/.DS_Store
|
24
|
+
test/samples/flyover2DP_syntheyes.txt
|
25
|
+
test/samples/megaTrack.action.3dtrack.stabilizer
|
26
|
+
test/samples/one_shake_tracker.txt
|
27
|
+
test/samples/one_shake_tracker_from_first.txt
|
28
|
+
test/samples/shake_tracker_nodes.shk
|
29
|
+
test/samples/shake_tracker_nodes_to_syntheyes.txt
|
30
|
+
test/samples/three_tracks_in_one_stabilizer.shk
|
31
|
+
test/samples/two_shake_trackers.txt
|
32
|
+
test/samples/two_tracks_in_one_tracker.shk
|
33
|
+
test/test_keyframe.rb
|
34
|
+
test/test_shake_export.rb
|
35
|
+
test/test_shake_script_import.rb
|
36
|
+
test/test_shake_text_import.rb
|
37
|
+
test/test_syntheyes_import.rb
|
data/README.txt
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
= Tracksperanto
|
2
|
+
|
3
|
+
* http://guerilla-di.org/tracksperanto
|
4
|
+
|
5
|
+
== Description
|
6
|
+
|
7
|
+
Tracksperanto is a universal 2D-track translator between many apps.
|
8
|
+
|
9
|
+
Import support:
|
10
|
+
* Shake script (one tracker node per tracker)
|
11
|
+
* Shake tracker node export (textfile with many tracks per file), also exported by Boujou and others
|
12
|
+
* PFTrack 2dt files
|
13
|
+
* Syntheyes 2D tracking data exports (UV coordinates)
|
14
|
+
|
15
|
+
Export support:
|
16
|
+
|
17
|
+
* Shake text file (many trackers per file), also accepted by Boujou
|
18
|
+
* PFTrack 2dt file (with residuals)
|
19
|
+
* Syntheyes 2D tracking data import (UV coordinates)
|
20
|
+
|
21
|
+
The main way to use Tracksperanto is to use the supplied "tracksperanto" binary, like so:
|
22
|
+
|
23
|
+
tracksperanto -f ShakeScript -w 1920 -h 1080 /Films/Blockbuster/Shots/001/script.shk
|
24
|
+
|
25
|
+
ShakeScript is the name of the translator that will be used to read the file (many apps export tracks as .txt files so
|
26
|
+
there is no way for us to autodetect them all). -w and -h stand for Width and Height and define the size of your comp (different
|
27
|
+
tracking apps use different coordinate systems and we need to know the size of the comp to properly convert these). You also have
|
28
|
+
additional options like -xs, -ys and --slip - consult the usage info for the tracksperanto binary.
|
29
|
+
|
30
|
+
The converted files will be saved in the same directory as the source, if resulting converted files already exist ++they will be overwritten without warning++.
|
31
|
+
|
32
|
+
== Modularity
|
33
|
+
|
34
|
+
Tracksperanto supports many export and import formats. It also can help when you need to import and export the same format,
|
35
|
+
but you need some operation applied to the result (like scaling a proxy track up). Internally, Tracksperanto talks
|
36
|
+
Exporters, Importers and Middlewares. Any processing chain usually works like this:
|
37
|
+
|
38
|
+
1) The tracker file is read and trackers and their keyframes are extracted, converting them to the internal representation.
|
39
|
+
For some formats you need to supply the width and height of the source material
|
40
|
+
2) The trackers and their keyframes are dumped to all export formats Tracksperanto supports, optionally passing through middleware
|
41
|
+
|
42
|
+
== Internal coordinate system
|
43
|
+
|
44
|
+
Frame numbers start from zero (frame 0 is first frame of the track).
|
45
|
+
|
46
|
+
Tracksperanto uses the Shake coordinates as base. Image is Y-positive, X-positive, absolute pixel values up and right (zero is in the
|
47
|
+
lower left corner). Some apps use a different coordinate system so translation will take place on import or on export, respectively.
|
48
|
+
|
49
|
+
We also use residual and not correlation (residual is how far the tracker strolls away, correlation is how sure the tracker is
|
50
|
+
about what it's doing). Residual is the inverse of correlation (with total correlation of one the residual excursion becomes zero).
|
51
|
+
|
52
|
+
== Limitations
|
53
|
+
|
54
|
+
Information about the search area, reference area and offset is not passed along (outside of scope for the app and different trackers handle
|
55
|
+
these differently, if at all). For some modules no residual will be passed along (3D tracking apps generally do not export residual with
|
56
|
+
backprojected 3D features).
|
data/Rakefile
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'hoe'
|
3
|
+
require './lib/tracksperanto'
|
4
|
+
|
5
|
+
|
6
|
+
# Disable spurious warnings when running tests, ActiveMagic cannot stand -w
|
7
|
+
Hoe::RUBY_FLAGS.replace ENV['RUBY_FLAGS'] || "-I#{%w(lib test).join(File::PATH_SEPARATOR)}" +
|
8
|
+
(Hoe::RUBY_DEBUG ? " #{RUBY_DEBUG}" : '')
|
9
|
+
|
10
|
+
Hoe.new('tracksperanto', Tracksperanto::VERSION) do |p|
|
11
|
+
p.rubyforge_name = 'guerilla-di'
|
12
|
+
p.developer('Julik Tarkhanov', 'me@julik.nl')
|
13
|
+
end
|
data/bin/tracksperanto
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# == Synopsis
|
3
|
+
#
|
4
|
+
# Translate a 2D track file from a single format to many others
|
5
|
+
#
|
6
|
+
# == Usage
|
7
|
+
#
|
8
|
+
# tracksperanto -f shakescript /Films/Blockbuster/Shots/001/script.shk -w 1920 -h 1080
|
9
|
+
#
|
10
|
+
# == Author
|
11
|
+
# Julik <me@julik.nl>
|
12
|
+
|
13
|
+
require File.dirname(__FILE__) + '/../lib/tracksperanto'
|
14
|
+
require File.dirname(__FILE__) + '/../lib/pipeline'
|
15
|
+
require 'optparse'
|
16
|
+
|
17
|
+
# Sane defaults
|
18
|
+
reader_klass = Tracksperanto::Import::ShakeScript
|
19
|
+
width = 1920
|
20
|
+
height = 1080
|
21
|
+
scale_x = 1.0
|
22
|
+
scale_y = 1.0
|
23
|
+
slip = 0
|
24
|
+
golden_tracks = false
|
25
|
+
|
26
|
+
readers = Tracksperanto::Import.constants.map{|e| e.to_s }.reject{|e| e == 'Base'}
|
27
|
+
informative_readers = readers.reject{|e| e == 'ShakeScript'}
|
28
|
+
|
29
|
+
parser = OptionParser.new do | p |
|
30
|
+
p.banner = "Usage: tracksperanto -f ShakeScript -w 1920 -h 1080 /Films/Blockbuster/Shots/001/script.shk"
|
31
|
+
p.on(" -f", "--from TRANSLATOR", String, "Use the specific import translator (defaults to ShakeScript, but can be \
|
32
|
+
#{informative_readers.join(', ')})") do | f |
|
33
|
+
begin
|
34
|
+
reader_klass = Tracksperanto::Import.const_get(f)
|
35
|
+
rescue NameError => e
|
36
|
+
reader_list = readers.join("\n\t")
|
37
|
+
STDERR.puts "Unknown reader #{f.inspect}, available readers:\n\t#{readers}"
|
38
|
+
exit(-1)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
p.on(" -w", "--width WIDTH_IN_PIXELS", Integer, "Absolute input comp width in pixels") { |w| width = w }
|
42
|
+
p.on(" -h", "--height HEIGHT_IN_PIXELS", Integer, "Absolute input comp height in pixels") {|w| height = w }
|
43
|
+
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 }
|
44
|
+
p.on(" -ys", "--yscale Y_SCALING_FACTOR", Float, "Scale the result in Y by this factor (1.0 is the default)") {|sy| scale_y = sy }
|
45
|
+
p.on(" -s", "--slip FRAMES", Integer, "Slip the result by this number of frames, positive is 'later'") {|sy| slip = sy }
|
46
|
+
p.on(" -g", "--golden", "Reset the residuals of all trackers to 0 (ignore correlation)") {|g_flag|
|
47
|
+
golden_tracks = g_flag
|
48
|
+
}
|
49
|
+
end
|
50
|
+
|
51
|
+
begin
|
52
|
+
parser.parse!
|
53
|
+
rescue OptionParser::MissingArgument => e
|
54
|
+
STDERR.puts "Unknown argument: #{e.message}"
|
55
|
+
puts parser
|
56
|
+
exit(-1)
|
57
|
+
end
|
58
|
+
|
59
|
+
input_file = ARGV.pop
|
60
|
+
if !input_file
|
61
|
+
STDERR.puts "No input file provided - should be the last argument"
|
62
|
+
puts parser
|
63
|
+
exit(-1)
|
64
|
+
end
|
65
|
+
|
66
|
+
pipe = Tracksperanto::Pipeline.new
|
67
|
+
pipe.run(input_file, width, height, reader_klass) do | scaler, slipper, golden |
|
68
|
+
slipper.slip = slip
|
69
|
+
scaler.x_factor = scale_x
|
70
|
+
scaler.y_factor = scale_y
|
71
|
+
golden.enabled = golden_tracks
|
72
|
+
end
|
73
|
+
|
74
|
+
puts "Converted #{pipe.converted_points} trackers"
|
data/lib/export/base.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
# Base exporter
|
2
|
+
class Tracksperanto::Export::Base
|
3
|
+
|
4
|
+
def self.inherited(by)
|
5
|
+
Tracksperanto.exporters << by
|
6
|
+
super
|
7
|
+
end
|
8
|
+
|
9
|
+
# Should return the suffix and extension of this export file (like "_flame.stabilizer"). It's a class
|
10
|
+
# method because it gets requested before the exporter is instantiated
|
11
|
+
def self.desc_and_extension
|
12
|
+
"data.txt"
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize(write_to_io)
|
16
|
+
@io = write_to_io
|
17
|
+
end
|
18
|
+
|
19
|
+
# Called on export start
|
20
|
+
def start_export( img_width, img_height)
|
21
|
+
end
|
22
|
+
|
23
|
+
# Called on export end
|
24
|
+
def end_export
|
25
|
+
end
|
26
|
+
|
27
|
+
# Called on tracker start, one for each tracker. Start of the next tracker
|
28
|
+
# signifies that the previous tracker has passed by
|
29
|
+
def start_tracker_segment(tracker_name)
|
30
|
+
end
|
31
|
+
|
32
|
+
# Called for each tracker keyframe
|
33
|
+
def export_point(at_frame_i, abs_float_x, abs_float_y, float_residual)
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
class Tracksperanto::Export::FlameStabilizer < Tracksperanto::Export::Base
|
2
|
+
PREAMBLE = '' #__DATA__.read
|
3
|
+
|
4
|
+
# Should return the suffix and extension of this export file (like "_flame.stabilizer")
|
5
|
+
def self.desc_and_extension
|
6
|
+
"flame.stabilizer"
|
7
|
+
end
|
8
|
+
|
9
|
+
def start_export(w, h)
|
10
|
+
@width = w, @height = h
|
11
|
+
end
|
12
|
+
|
13
|
+
def start_tracker_segment(tracker_name)
|
14
|
+
@tracker_count ||= 0
|
15
|
+
@tracker_count += 1
|
16
|
+
end
|
17
|
+
|
18
|
+
def end_export
|
19
|
+
preamble = PREAMBLE % [ @tracker_count, @width, @height]
|
20
|
+
end
|
21
|
+
|
22
|
+
def export_point(frame, abs_float_x, abs_float_y, float_residual)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
__END__
|
27
|
+
StabilizerFileVersion 5.0
|
28
|
+
CreationDate Tue Dec 9 21:02:02 2008
|
29
|
+
|
30
|
+
|
31
|
+
NbTrackers %d
|
32
|
+
Selected 0
|
33
|
+
FrameWidth %d
|
34
|
+
FrameHeight %d
|
35
|
+
AutoKey yes
|
36
|
+
MotionPath yes
|
37
|
+
Icons yes
|
38
|
+
AutoPan no
|
39
|
+
EditMode 1
|
40
|
+
Format 0
|
41
|
+
Padding
|
42
|
+
Red 0
|
43
|
+
Green 0
|
44
|
+
Blue 0
|
45
|
+
Oversampling no
|
46
|
+
Opacity 50
|
47
|
+
Zoom 3
|
48
|
+
Field no
|
49
|
+
Backward no
|
50
|
+
Anim
|
data/lib/export/mux.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# Multiplexor. Does not inherit Base so that it does not get used as a translator
|
2
|
+
class Tracksperanto::Export::Mux
|
3
|
+
attr_accessor :outputs
|
4
|
+
|
5
|
+
def initialize(*outputs)
|
6
|
+
@outputs = outputs.flatten
|
7
|
+
end
|
8
|
+
|
9
|
+
# Called on export start
|
10
|
+
def start_export( img_width, img_height)
|
11
|
+
@outputs.each do | output |
|
12
|
+
output.start_export( img_width, img_height)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
# Called on tracker start, one for each tracker
|
17
|
+
def start_tracker_segment(tracker_name)
|
18
|
+
@outputs.each do | output |
|
19
|
+
output.start_tracker_segment(tracker_name)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# Called for each tracker keyframe
|
24
|
+
def export_point(at_frame_i, abs_float_x, abs_float_y, float_residual)
|
25
|
+
@outputs.each do | output |
|
26
|
+
output.export_point(at_frame_i, abs_float_x, abs_float_y, float_residual)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def end_export
|
31
|
+
@outputs.each{|o| o.end_export }
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
class Tracksperanto::Export::Pftrack < Tracksperanto::Export::Base
|
2
|
+
|
3
|
+
# Should return the suffix and extension of this export file (like "_flame.stabilizer")
|
4
|
+
def self.desc_and_extension
|
5
|
+
"pftrack.2dt"
|
6
|
+
end
|
7
|
+
|
8
|
+
def start_tracker_segment(tracker_name)
|
9
|
+
# If there was a previous tracker, write it out
|
10
|
+
# - now we know how many keyframes it has
|
11
|
+
if @prev_tracker && @prev_tracker.any?
|
12
|
+
block = [
|
13
|
+
"\n",
|
14
|
+
@tracker_name.inspect, # "autoquotes"
|
15
|
+
@prev_tracker.length,
|
16
|
+
@prev_tracker.join("\n")
|
17
|
+
]
|
18
|
+
@io.puts block.join("\n")
|
19
|
+
end
|
20
|
+
|
21
|
+
# Setup for the next tracker
|
22
|
+
@prev_tracker = []
|
23
|
+
@tracker_name = tracker_name
|
24
|
+
end
|
25
|
+
|
26
|
+
def export_point(frame, abs_float_x, abs_float_y, float_residual)
|
27
|
+
line = "%s %.3f %.3f %.3f" % [frame, abs_float_x, abs_float_y, float_residual]
|
28
|
+
@prev_tracker << line
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
class Tracksperanto::Export::ShakeText < Tracksperanto::Export::Base
|
2
|
+
PREAMBLE = "TrackName %s\n Frame X Y Correlation\n"
|
3
|
+
POSTAMBLE = "\n"
|
4
|
+
|
5
|
+
# Should return the suffix and extension of this export file (like "_flame.stabilizer")
|
6
|
+
def self.desc_and_extension
|
7
|
+
"shake_trackers.txt"
|
8
|
+
end
|
9
|
+
|
10
|
+
def start_tracker_segment(tracker_name)
|
11
|
+
if @any_tracks
|
12
|
+
@io.puts POSTAMBLE
|
13
|
+
else
|
14
|
+
@any_tracks = true
|
15
|
+
end
|
16
|
+
|
17
|
+
@io.puts PREAMBLE % tracker_name
|
18
|
+
end
|
19
|
+
|
20
|
+
def end_export
|
21
|
+
@io << "\n"
|
22
|
+
end
|
23
|
+
|
24
|
+
def export_point(frame, abs_float_x, abs_float_y, float_residual)
|
25
|
+
# Shake starts from frame 1, not 0
|
26
|
+
line = " %.2f %.3f %.3f %.3f" % [frame + 1, abs_float_x, abs_float_y, 1 - float_residual]
|
27
|
+
@io.puts line
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
class Tracksperanto::Export::SynthEyes < Tracksperanto::Export::Base
|
2
|
+
|
3
|
+
# Should return the suffix and extension of this export file (like "_flame.stabilizer")
|
4
|
+
def self.desc_and_extension
|
5
|
+
"syntheyes_2dt.txt"
|
6
|
+
end
|
7
|
+
|
8
|
+
def start_export( img_width, img_height)
|
9
|
+
@width, @height = img_width, img_height
|
10
|
+
end
|
11
|
+
|
12
|
+
def start_tracker_segment(tracker_name)
|
13
|
+
@tracker_name = tracker_name
|
14
|
+
end
|
15
|
+
|
16
|
+
def export_point(frame, abs_float_x, abs_float_y, float_residual)
|
17
|
+
values = [@tracker_name, frame] + syntheyes_coords(abs_float_x, abs_float_y)
|
18
|
+
@io.puts("%s %d %.6f %.6f 30" % values)
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
# Syntheyes wants very special coordinates, Y down X right,
|
24
|
+
# 0 is center and values are UV float -1 to 1, doubled
|
25
|
+
def syntheyes_coords(abs_x, abs_y)
|
26
|
+
w, h = 2560, 1080
|
27
|
+
x = (abs_x / @width.to_f) - 0.5
|
28
|
+
y = (abs_y / @height.to_f) - 0.5
|
29
|
+
# .2 to -.3, y is reversed and coords are double
|
30
|
+
[x * 2, y * -2]
|
31
|
+
end
|
32
|
+
end
|
data/lib/import/base.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'stringio'
|
2
|
+
|
3
|
+
class Tracksperanto::Import::Base
|
4
|
+
include Tracksperanto::Safety
|
5
|
+
|
6
|
+
# The original width of the tracked image
|
7
|
+
# Some importers need it
|
8
|
+
attr_accessor :width
|
9
|
+
|
10
|
+
# The original height of the original image.
|
11
|
+
# Some importers need it
|
12
|
+
attr_accessor :height
|
13
|
+
safe_reader :width, :height
|
14
|
+
|
15
|
+
def self.inherited(by)
|
16
|
+
Tracksperanto.importers << by
|
17
|
+
super
|
18
|
+
end
|
19
|
+
|
20
|
+
# Should return an array of Tracksperanto::Tracker objects
|
21
|
+
def parse(track_file_content)
|
22
|
+
[]
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'stringio'
|
2
|
+
|
3
|
+
class Tracksperanto::Import::FlameStabilizer < Tracksperanto::Import::Base
|
4
|
+
# Flame records channels in it's .stabilizer file. Per tracker, we use tracker1/track/x and tracker1/track/y as the base
|
5
|
+
# tracking value. Then, the tracker1/shift/x and tracker1/shift/y are added to it. The problem is that when we track backwards
|
6
|
+
# the main reference keyframe for the x and y coordinates that sets the base for the animation might be at the last frame, at
|
7
|
+
# a frame in the middle or in the end of the setup. We have to pluck it out and then we compute the shift relative to the values
|
8
|
+
# in this main frame. Obviously we discard the track width and search width information as we cannot use it in any meaningful way.
|
9
|
+
#
|
10
|
+
# Here is how the relevant portions look like this (note the tab indents, not spaces, indentation starts at hashmark)
|
11
|
+
#Channel tracker1/shift/x
|
12
|
+
# Extrapolation linear
|
13
|
+
# Value 0
|
14
|
+
# Size 185
|
15
|
+
# KeyVersion 1
|
16
|
+
# Key 0
|
17
|
+
# Frame 1
|
18
|
+
# Value 0
|
19
|
+
# Interpolation linear
|
20
|
+
# RightSlope 0.15802
|
21
|
+
# LeftSlope 0.15802
|
22
|
+
# End
|
23
|
+
# Key 1
|
24
|
+
#
|
25
|
+
# This is in big lines:
|
26
|
+
# (tabs)Key(space)Value
|
27
|
+
def parse(stabilizer_setup_content)
|
28
|
+
trackers = []
|
29
|
+
|
30
|
+
io = StringIO.new(stabilizer_setup_content)
|
31
|
+
|
32
|
+
trackers
|
33
|
+
end
|
34
|
+
end
|