mirror of
https://github.com/unclshura/splitter.git
synced 2026-06-22 00:22:01 +00:00
Command line switches for changing various internal parameters.
This commit is contained in:
parent
2b412694fb
commit
a6b9d9c069
@ -17,13 +17,14 @@ public sealed class CameraController
|
||||
private readonly int _cropWidth;
|
||||
private readonly int _cropHeight;
|
||||
private readonly KalmanTracker _kalman;
|
||||
private readonly CommandLine _cmd;
|
||||
private int _dropoutCounter;
|
||||
|
||||
// --- Dropout tolerance ---
|
||||
private const int DropoutToleranceFrames = 20;
|
||||
private const float EmaFactor = 0.65f; // smoother but responsive
|
||||
private const float CameraEasing = 0.03f; // stronger follow-through
|
||||
private const int LostFreezeFrames = 60; // 2 seconds at 30 FPS
|
||||
private int _dropoutToleranceFrames = 20;
|
||||
private float _emaFactor = 0.65f; // smoother but responsive
|
||||
private float _cameraEasing = 0.03f; // stronger follow-through
|
||||
private int _lostFreezeFrames = 60; // 2 seconds at 30 FPS
|
||||
|
||||
|
||||
private int _lostFrames;
|
||||
@ -39,7 +40,8 @@ public sealed class CameraController
|
||||
int videoHeight,
|
||||
int cropWidth,
|
||||
int cropHeight,
|
||||
KalmanTracker kalman
|
||||
KalmanTracker kalman,
|
||||
CommandLine cmd
|
||||
)
|
||||
{
|
||||
_videoWidth = videoWidth;
|
||||
@ -47,13 +49,20 @@ public sealed class CameraController
|
||||
_cropWidth = cropWidth;
|
||||
_cropHeight = cropHeight;
|
||||
_kalman = kalman;
|
||||
|
||||
_cameraCenter = new Point2f(videoWidth / 2f, videoHeight / 2f);
|
||||
_cmd = cmd;
|
||||
_cameraCenter = DefaultCenter;
|
||||
_state = TrackState.Tracking;
|
||||
|
||||
cmd.Override(ref _dropoutToleranceFrames, "DropoutToleranceFrames");
|
||||
cmd.Override(ref _emaFactor, "EmaFactor");
|
||||
cmd.Override(ref _cameraEasing, "CameraEasing");
|
||||
cmd.Override(ref _lostFreezeFrames, "LostFreezeFrames");
|
||||
|
||||
_kalman.Reset(_cameraCenter);
|
||||
}
|
||||
|
||||
private Point2f DefaultCenter => _cmd.GravitateTo ?? new Point2f(_videoWidth / 2f, _videoHeight / 2f);
|
||||
|
||||
public int LostFrames => _lostFrames;
|
||||
public Point2f CameraCenter => _cameraCenter;
|
||||
public TrackState State => _state;
|
||||
@ -78,7 +87,7 @@ public sealed class CameraController
|
||||
// ---------------------------------------------------------
|
||||
if (!objectCenter.HasValue)
|
||||
{
|
||||
if (_dropoutCounter < DropoutToleranceFrames)
|
||||
if (_dropoutCounter < _dropoutToleranceFrames)
|
||||
{
|
||||
objectCenter = _kalman.LastMeasurement;
|
||||
_dropoutCounter++;
|
||||
@ -96,7 +105,7 @@ public sealed class CameraController
|
||||
{
|
||||
_lostFrames++;
|
||||
|
||||
if (_lostFrames <= LostFreezeFrames)
|
||||
if (_lostFrames <= _lostFreezeFrames)
|
||||
{
|
||||
_state = TrackState.LostFreeze;
|
||||
objectCenter = null;
|
||||
@ -104,7 +113,7 @@ public sealed class CameraController
|
||||
else
|
||||
{
|
||||
_state = TrackState.LostDrift;
|
||||
objectCenter = new Point2f(_videoWidth / 2f, _videoHeight / 2f);
|
||||
objectCenter = DefaultCenter;
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -124,13 +133,13 @@ public sealed class CameraController
|
||||
// NEW: EMA smoothing
|
||||
// ---------------------------------------------------------
|
||||
smoothedCenter = new Point2f(
|
||||
smoothedCenter.X * (1 - EmaFactor) + _cameraCenter.X * EmaFactor,
|
||||
smoothedCenter.Y * (1 - EmaFactor) + _cameraCenter.Y * EmaFactor
|
||||
smoothedCenter.X * (1 - _emaFactor) + _cameraCenter.X * _emaFactor,
|
||||
smoothedCenter.Y * (1 - _emaFactor) + _cameraCenter.Y * _emaFactor
|
||||
);
|
||||
|
||||
_cameraCenter = new Point2f(
|
||||
_cameraCenter.X + (smoothedCenter.X - _cameraCenter.X) * CameraEasing,
|
||||
_cameraCenter.Y + (smoothedCenter.Y - _cameraCenter.Y) * CameraEasing);
|
||||
_cameraCenter.X + (smoothedCenter.X - _cameraCenter.X) * _cameraEasing,
|
||||
_cameraCenter.Y + (smoothedCenter.Y - _cameraCenter.Y) * _cameraEasing);
|
||||
|
||||
}
|
||||
else if (_state == TrackState.LostFreeze)
|
||||
@ -165,6 +174,7 @@ public sealed class CameraController
|
||||
y = Math.Clamp(y, 0, _videoHeight - _cropHeight);
|
||||
|
||||
_roi = new Rect(x, y, _cropWidth, _cropHeight);
|
||||
|
||||
_smoothedCenter = smoothedCenter;
|
||||
_objectBox = objectBox;
|
||||
_objectCenter = objectCenter;
|
||||
|
||||
@ -10,6 +10,7 @@ public sealed class CommandLine
|
||||
public string InputFile { get; private init; }
|
||||
public string OutputFolder { get; private init; }
|
||||
public (int width, int height)? Crop { get; private init; }
|
||||
public Point2f? GravitateTo { get; private init; }
|
||||
public string? Mask { get; private init; }
|
||||
public bool Debug { get; private init; }
|
||||
public string? Detect { get; private init; }
|
||||
@ -19,6 +20,7 @@ public sealed class CommandLine
|
||||
public bool EstimateOnly { get; private init; }
|
||||
public bool ForceFixed { get; private init; }
|
||||
public bool SingleThreaded { get; private init; }
|
||||
public Dictionary<string, string> Parameters { get; } = [];
|
||||
|
||||
public bool IsValid => !string.IsNullOrEmpty(InputFile) && !string.IsNullOrEmpty(OutputFolder);
|
||||
|
||||
@ -84,6 +86,11 @@ public sealed class CommandLine
|
||||
{
|
||||
SingleThreaded = true;
|
||||
}
|
||||
else if (arg.StartsWith("--gravitate="))
|
||||
{
|
||||
var val = arg.Substring("--gravitate=".Length);
|
||||
GravitateTo = ParseGravitate(val);
|
||||
}
|
||||
else if (arg.StartsWith("--duration="))
|
||||
{
|
||||
var dur = arg.Substring("--duration=".Length);
|
||||
@ -94,6 +101,17 @@ public sealed class CommandLine
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (arg.StartsWith("-p:", StringComparison.Ordinal))
|
||||
{
|
||||
var spec = arg.Substring("-p:".Length);
|
||||
if (!TryParseParameter(spec, out var key, out var value))
|
||||
{
|
||||
Console.WriteLine($"Invalid -p parameter: {spec}");
|
||||
return;
|
||||
}
|
||||
|
||||
Parameters[key] = value;
|
||||
}
|
||||
else if (arg == "--estimate")
|
||||
{
|
||||
EstimateOnly = true;
|
||||
@ -105,6 +123,63 @@ public sealed class CommandLine
|
||||
}
|
||||
}
|
||||
|
||||
public void Override<T>(ref T member, string name)
|
||||
{
|
||||
if (!Parameters.TryGetValue(name, out var raw))
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
// Convert.ChangeType handles int, float, double, etc.
|
||||
var converted = (T)Convert.ChangeType(
|
||||
raw,
|
||||
typeof(T),
|
||||
CultureInfo.InvariantCulture
|
||||
);
|
||||
|
||||
member = converted;
|
||||
}
|
||||
catch
|
||||
{
|
||||
Console.WriteLine($"Invalid value for parameter '{name}': {raw}");
|
||||
}
|
||||
}
|
||||
|
||||
private static bool TryParseParameter(string spec, out string key, out string value)
|
||||
{
|
||||
key = "";
|
||||
value = "";
|
||||
|
||||
var idx = spec.IndexOf('=');
|
||||
if (idx <= 0 || idx == spec.Length - 1)
|
||||
return false;
|
||||
|
||||
key = spec.Substring(0, idx).Trim();
|
||||
value = spec.Substring(idx + 1).Trim();
|
||||
|
||||
return key.Length > 0;
|
||||
}
|
||||
|
||||
private static Point2f? ParseGravitate(string value)
|
||||
{
|
||||
// Expected format: "<x>:<y>"
|
||||
var parts = value.Split(':');
|
||||
if (parts.Length != 2)
|
||||
return null;
|
||||
|
||||
if (!float.TryParse(parts[0], NumberStyles.Float, CultureInfo.InvariantCulture, out var x))
|
||||
return null;
|
||||
|
||||
if (!float.TryParse(parts[1], NumberStyles.Float, CultureInfo.InvariantCulture, out var y))
|
||||
return null;
|
||||
|
||||
// Normalized range check (0.0–1.0)
|
||||
if (x < 0f || x > 1f || y < 0f || y > 1f)
|
||||
return null;
|
||||
|
||||
return new Point2f(x, y);
|
||||
}
|
||||
|
||||
private static (int width, int height)? ParseCrop(string v)
|
||||
{
|
||||
// Default vertical Full HD for YouTube Shorts
|
||||
@ -201,6 +276,10 @@ Options:
|
||||
--detect=<name> Object detector to use for tracking.
|
||||
Values: face (UltraFace), body (YoloOnnx, default), none (no tracking, just a center)
|
||||
|
||||
--gravitate=<x:y> Gravitate towards a specific point (x, y) in the video frame.
|
||||
Coordinates are normalized (0.0 to 1.0).
|
||||
Example: --gravitate=0.2:0.5 (gravitate towards left-center)
|
||||
|
||||
--text Display log in plain text.
|
||||
|
||||
--single-thread Run in single-threaded mode (no parallel ffmpeg processes).
|
||||
@ -208,6 +287,15 @@ Options:
|
||||
|
||||
--debug Show debug overlay during face tracking.
|
||||
|
||||
-p:<name>=<value> Set a custom parameter for the object detector.
|
||||
Example: -p:confidence=0.5
|
||||
|
||||
Tracking splitter defaults:
|
||||
DropoutToleranceFrames = 20;
|
||||
EmaFactor = 0.65;
|
||||
CameraEasing = 0.03;
|
||||
LostFreezeFrames = 60;
|
||||
|
||||
Passthrough:
|
||||
Anything after -- is passed directly to ffmpeg.
|
||||
|
||||
|
||||
@ -16,8 +16,9 @@ public class TrackingSplitter : LoggingBase, ISegmentProcessor, IDisposable
|
||||
private readonly bool _plainText;
|
||||
|
||||
private readonly IObjectDetector _detector;
|
||||
private readonly CommandLine _cmd;
|
||||
|
||||
public TrackingSplitter(int segmentNo, int cropWidth, int cropHeight, bool debugOverlay, bool plainText, IObjectDetector detector)
|
||||
public TrackingSplitter(int segmentNo, int cropWidth, int cropHeight, bool debugOverlay, bool plainText, IObjectDetector detector, CommandLine cmd)
|
||||
: base(segmentNo)
|
||||
{
|
||||
_segmentNo = segmentNo;
|
||||
@ -26,6 +27,7 @@ public class TrackingSplitter : LoggingBase, ISegmentProcessor, IDisposable
|
||||
_debugOverlay = debugOverlay;
|
||||
_plainText = plainText;
|
||||
_detector = detector;
|
||||
_cmd = cmd;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
@ -83,7 +85,8 @@ public class TrackingSplitter : LoggingBase, ISegmentProcessor, IDisposable
|
||||
videoHeight,
|
||||
originalCropWidth,
|
||||
originalCropHeight,
|
||||
kalman
|
||||
kalman,
|
||||
_cmd
|
||||
);
|
||||
|
||||
var startTime = DateTime.UtcNow;
|
||||
|
||||
@ -87,7 +87,7 @@ static class Program
|
||||
"body" => new YoloOnnxObjectDetector(),
|
||||
_ => throw new InvalidOperationException($"Unknown detector: {detect}")
|
||||
};
|
||||
return new TrackingSplitter(i, crop.Value.width, crop.Value.height, debug, cmd.PlainText, detector);
|
||||
return new TrackingSplitter(i, crop.Value.width, crop.Value.height, debug, cmd.PlainText, detector, cmd);
|
||||
};
|
||||
}
|
||||
else
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user