-
Notifications
You must be signed in to change notification settings - Fork 1
/
RetrievalBatch.cs
278 lines (236 loc) · 10.1 KB
/
RetrievalBatch.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NMotive;
namespace MotiveBatchProcessor.Examples
{
/// <summary>
/// Motive Batch Processor script for running processing retieval data from Filbury.
/// </summary>
public class RetrievalBatch : ITakeProcessingScript
{
delegate bool PrintKeyframePredicate(int frameIndex);
#region Instance Variables -------------------------------------------
/// <summary>
/// This variable will hold the argument string that was entered by
/// the user when the script is run by the batch processor.
/// </summary>
private string[] mBatchProcessorArguments;
#endregion Instance Variables
#region ITakeProcessingScriptWithArgs interface implementation -------
/// <summary>
/// The argument string entered by the user when running the script in
/// the batch processor.
/// </summary>
public string[] Arguments
{
set { mBatchProcessorArguments = value; }
}
/// <summary>
/// This string will be placed next to the text box where the
/// user enters the maximum gap size to fill.
/// </summary>
public string ArgumentLabel
{
get { return "Enter maximum gap size to fill:"; }
}
/// <summary>
/// The default value.
/// </summary>
public string[] DefaultArguments
{
get { return new string[0]; }
}
/// <summary>
/// After the user has entered the argument string, the batch processor will
/// call this function to validate it. In this case we expect an positive
/// integer value to be entered.
/// </summary>
/// <param name="argString">The user entered argument string.</param>
/// <returns>The result of the validation. If the string represents
/// a valid integer Result.Success is set to true. If it does not
/// represent a valid positive integer Result.Success is set to false
/// and Result.Message contains further information.</returns>
public Result ValidateArguments(string[] argString)
{
int n;
if (argString.Length >= 1)
{
if (int.TryParse(argString[0], out n))
{
if (int.Parse(argString[0]) >= 0)
{
// Returns true if the input is a positive integer.
return new Result(true, "");
}
else
{
return new Result(false, argString[0] + " is not a positive integer.");
}
}
else
{
return new Result(false, argString[0] + " is not a valid integer.");
}
}
return new Result(false, "Too few arguments.");
}
/// <summary>
/// The <c>ProcessTake</c> function is from the <c>ITakeProcessingScript</c> interface.
/// Creates or reprocesses 3D data for a given take by reconstructing and
/// auto-labeling it. Updates the loaded take instead of creating a new one.
/// </summary>
/// <param name="take">The take to export.</param>
/// <param name="progress">Progress indicator object. Shows the current take
/// and what is currently being processed.</param>
/// <returns>The same file with new 3D data.</returns>
///
/// /// Performs the gap filling task on the given take.
/// </summary>
/// <param name="take">A take.</param>
/// <param name="progress">Progress indicator.</param>
/// <returns>The result of gap filling.</returns>
public Result ProcessTake(Take take, ProgressIndicator progress)
{
// Remove solve, if solved already
take.RemoveSolve();
// Set reconstruction settings to use.
string fileName = "D:\\nicRobData\\reconstruction_settings_retrieval.mup";
Result res = Settings.ImportMotiveProfile(fileName);
if (!res.Success)
{
return res;
}
// Construct an NMotive Trajectorizer object, then Process the take.
Trajectorizer traj = new Trajectorizer(progress);
traj.Process(take, TrajectorizerOption.Reconstruct);
take.Save();
// Trim around gaps using smart trim
TrimTails trimTails = new TrimTails();
trimTails.Automatic = false;
trimTails.GapSizeThreshold = 2;
trimTails.LeadingTrimSize = 4;
trimTails.TrailingTrimSize = 4;
trimTails.MinimumSegmentSize = 4;
trimTails.Process(take);
// Autolabel
traj.Process(take, TrajectorizerOption.AutoLabel);
take.Save();
// Linear interpolate small gaps
int maxGapSize = 10;
FillGaps fill = new FillGaps(progress);
fill.InterpolationMode = InterpolationType.Linear; // Constant, Linear, Hermite (Cubic), PatternBased, ModelBased
fill.MaxGapFillWidth = maxGapSize;
Result fillResult = fill.Process(take);
// Spline interpolate medium gaps
maxGapSize = 60;
fill = new FillGaps(progress);
fill.InterpolationMode = InterpolationType.Hermite; // Constant, Linear, Hermite (Cubic), PatternBased, ModelBased
fill.MaxGapFillWidth = maxGapSize;
fillResult = fill.Process(take);
// Solve rigid bodies
take.Solve();
// Remove unlabelled markers
List<RealMarker> list = take.Scene.AllMarkers();
for (int i = 0; list.Count > i; ++i)
{
if (list[i].IsLabeled == false)
{
take.Scene.RemoveNode(list[i].Name.ToString());
}
}
// Save
take.Save();
// Only interested in the scannercast rigid body
NodeWarehouse nodeWarehouse = take.Scene;
List<AnimatedNode> allRigidBodies = nodeWarehouse.AllRigidBodies();
string newName = "Scannercast";
if (allRigidBodies.Count == 1)
{
take.Scene.AllRigidBodies()[0].Name = newName;
}
else
{
// Initialize the highest node and its height.
AnimatedNode highestNode = null;
float highestHeight = float.MinValue;
// Iterate through all rigid bodies.
foreach (AnimatedNode node in allRigidBodies)
{
// Get the height of the current node.
float currentHeight = node.Translation(take.FullFrameRange.Center).Z;
// If the current node is higher than the highest node so far, update the highest node and its height.
if (currentHeight > highestHeight)
{
highestNode = node;
highestHeight = currentHeight;
}
}
// Rename the highest node.
if (highestNode != null)
{
highestNode.Name = newName;
}
}
// Disable assets that are not the scannercast
foreach (AnimatedNode rigidBody in allRigidBodies)
{
if (!(rigidBody.Name == newName))
{
rigidBody.Active = false;
}
}
// Filter the data.
Filter filter = new Filter();
filter.CutOffFrequency = 8;
filter.DataRate = take.FrameRate;
filter.Process(take);
// Solve rigid bodies again.
take.Solve();
// Final save.
take.Save();
// Export
// Construct an NMotive CSV exporter object with the desired
// options. We will write CSV data for markers and assets.
CSVExporter exporter = new CSVExporter
{
//-== CSVExporter Class ==-
RotationType = Rotation.QuaternionFormat, // QuaternionFormat, XYZ, XZY, YXZ, YZX, ZXY, ZYX
Units = LengthUnits.Units_Millimeters,
UseWorldSapceCoordinates = true,
WriteBoneMarkers = false,
WriteBones = false,
WriteHeader = true,
WriteMarkers = true,
WriteQualityStats = true,
WriteRigidBodies = true,
WriteRigidBodyMarkers = true
};
// Construct the output CSV file. The output file will be co-located with the
// take file and have the same name as the take file, but with an '.csv'
// file extension and a different BIDS description
string outputFileName = Path.GetFileNameWithoutExtension(take.FileName);
int remEnd = 9;
string newFileDescription = "ScannercastRigidBody" + ".csv";
// Check if the outputFileName is longer than X
if (outputFileName.Length > remEnd)
{
// Remove the last X characters and add the new file ending
outputFileName = outputFileName.Substring(0, outputFileName.Length - remEnd) + newFileDescription;
}
else
{
outputFileName = outputFileName + newFileDescription;
}
string outputDirectory = Path.GetDirectoryName(take.FileName);
string outputFile = Path.Combine(outputDirectory, outputFileName);
// Do the export and return the Export functions result object.
progress.SetMessage("Writing to File");
progress.SetProgress((float)0.1);
return exporter.Export(take, outputFile, true);
}
#endregion ITakeProcessingScriptWithArgs interface implementation
}
}