mirror of
https://github.com/unclshura/splitter.git
synced 2026-06-22 00:22:01 +00:00
Automatic crop size calculation. GravitateTo is in sync. Defaults appied at start.
This commit is contained in:
parent
c6ca4fcbb6
commit
2dc7b050c8
@ -7,12 +7,15 @@ public sealed class ActionToIconConverter : IValueConverter
|
|||||||
{
|
{
|
||||||
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
|
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
|
||||||
{
|
{
|
||||||
return value switch
|
if (value == null)
|
||||||
{
|
return null;
|
||||||
"crop" => "\uf125", // FA7 crop
|
|
||||||
"rotate" => "\uf2f1", // FA7 rotate
|
var p = System.Convert.ToInt32(value);
|
||||||
_ => null
|
|
||||||
};
|
return p == 0
|
||||||
|
? "\uf125" // FA7 crop
|
||||||
|
: "\uf2f1" // FA7 rotate
|
||||||
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
|
public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
|
||||||
|
|||||||
@ -1,6 +1,4 @@
|
|||||||
using Avalonia;
|
namespace Splitter_UI.Models;
|
||||||
|
|
||||||
namespace Splitter_UI.Models;
|
|
||||||
|
|
||||||
public class PreviewData
|
public class PreviewData
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1,8 +1,6 @@
|
|||||||
using Avalonia;
|
using Avalonia;
|
||||||
using Avalonia.Media;
|
using Avalonia.Media;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using splitter.algo;
|
|
||||||
using splitter.tui;
|
|
||||||
|
|
||||||
namespace Splitter_UI;
|
namespace Splitter_UI;
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,4 @@
|
|||||||
using NcnnDotNet.Layers;
|
using OpenCvSharp.Dnn;
|
||||||
using OpenCvSharp;
|
|
||||||
using splitter.tui;
|
|
||||||
|
|
||||||
namespace Splitter_UI.Services;
|
namespace Splitter_UI.Services;
|
||||||
|
|
||||||
@ -15,19 +13,63 @@ public sealed class AutoDecisionService(IThumbnailService _thumbnails, IFileProb
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
job.GravitateTo = new(0.5f, 0.5f);
|
||||||
|
job.OverrideTargetDuration = 58.0;
|
||||||
|
job.Mask = "[NAME]_seg[NN].[EXT]";
|
||||||
|
job.OutputFolder = Path.Combine(Path.GetDirectoryName(job.InputFile)!, "splitter");
|
||||||
|
|
||||||
job.Probe = await _fileProbe.ProbeAsync(job.InputFile);
|
job.Probe = await _fileProbe.ProbeAsync(job.InputFile);
|
||||||
job.Thumbnail = await _thumbnails.CreateThumbnailAsync(job.InputFile, job.Probe, rotateDegree: job.Rotate);
|
job.Thumbnail = await _thumbnails.CreateThumbnailAsync(job.InputFile, job.Probe, rotateDegree: job.Rotate);
|
||||||
|
|
||||||
var sampler = new VideoRotationSampler(null);
|
if (job.Probe.Width > job.Probe.Height)
|
||||||
job.Rotate = await sampler.DetectRotationAsync(job.InputFile, job.Probe.Duration);
|
{
|
||||||
job.SuggestedAction = job.Rotate == 0 ? "crop" : "rotate";
|
|
||||||
|
|
||||||
if (job.SuggestedAction == "crop")
|
|
||||||
job.Detect = "body";
|
job.Detect = "body";
|
||||||
|
job.Rotate = 0;
|
||||||
|
|
||||||
|
CalculateCrop(job);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var sampler = new VideoRotationSampler(null);
|
||||||
|
job.Rotate = await sampler.DetectRotationAsync(job.InputFile, job.Probe.Duration);
|
||||||
|
job.Detect = job.Rotate == 0 ? null : "body";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
_log.LogError($"Error creating thumbnail for {Path.GetFileName(job.InputFile)}: {ex.Message}");
|
_log.LogError($"Error creating thumbnail for {Path.GetFileName(job.InputFile)}: {ex.Message}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void CalculateCrop(JobViewModel job)
|
||||||
|
{
|
||||||
|
var targetAR = (float)CommandLine.DefaultW / CommandLine.DefaultH;
|
||||||
|
var pixelAspect = job.Probe!.Sar.X / job.Probe.Sar.Y;
|
||||||
|
|
||||||
|
float srcW = job.Probe.Width * pixelAspect;
|
||||||
|
float srcH = job.Probe.Height;
|
||||||
|
var srcAR = srcW / srcH;
|
||||||
|
|
||||||
|
float cropH = srcH;
|
||||||
|
float cropW = cropH * targetAR;
|
||||||
|
|
||||||
|
if (cropW > srcW)
|
||||||
|
{
|
||||||
|
cropW = srcW;
|
||||||
|
cropH = cropW / targetAR;
|
||||||
|
}
|
||||||
|
|
||||||
|
float x = (srcW - cropW) * 0.5f;
|
||||||
|
float y = (srcH - cropH) * 0.5f;
|
||||||
|
|
||||||
|
float invPixelAspect = 1f / pixelAspect;
|
||||||
|
|
||||||
|
float cropW_px = cropW * invPixelAspect;
|
||||||
|
float cropH_px = cropH;
|
||||||
|
|
||||||
|
float x_px = x * invPixelAspect;
|
||||||
|
float y_px = y;
|
||||||
|
|
||||||
|
job.CropText = $"{(int)MathF.Round(cropW_px)},{(int)MathF.Round(cropH_px)}";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using Avalonia;
|
using Avalonia;
|
||||||
using Avalonia.Media.Imaging;
|
using Avalonia.Media.Imaging;
|
||||||
using OpenCvSharp;
|
|
||||||
|
|
||||||
namespace Splitter_UI.Services;
|
namespace Splitter_UI.Services;
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,4 @@
|
|||||||
using OpenCvSharp;
|
namespace Splitter_UI.Services;
|
||||||
using splitter.algo;
|
|
||||||
|
|
||||||
namespace Splitter_UI.Services;
|
|
||||||
|
|
||||||
internal class DummyDetector : IObjectDetector
|
internal class DummyDetector : IObjectDetector
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1,6 +1,4 @@
|
|||||||
using splitter.probe;
|
namespace Splitter_UI.Services;
|
||||||
|
|
||||||
namespace Splitter_UI.Services;
|
|
||||||
|
|
||||||
public sealed class FileProbeService : IFileProbeService
|
public sealed class FileProbeService : IFileProbeService
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1,6 +1,4 @@
|
|||||||
using splitter.tui;
|
namespace Splitter_UI.Services;
|
||||||
|
|
||||||
namespace Splitter_UI.Services;
|
|
||||||
|
|
||||||
internal class GlobalLogger(ILogService _logService) : ILogger
|
internal class GlobalLogger(ILogService _logService) : ILogger
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1,6 +1,4 @@
|
|||||||
using splitter.probe;
|
namespace Splitter_UI.Services;
|
||||||
|
|
||||||
namespace Splitter_UI.Services;
|
|
||||||
|
|
||||||
public interface IFileProbeService
|
public interface IFileProbeService
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
using Avalonia.Media.Imaging;
|
using Avalonia.Media.Imaging;
|
||||||
using splitter.probe;
|
|
||||||
|
|
||||||
namespace Splitter_UI.Services;
|
namespace Splitter_UI.Services;
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,4 @@
|
|||||||
using OpenCvSharp;
|
namespace Splitter_UI.Services;
|
||||||
using splitter.algo;
|
|
||||||
|
|
||||||
namespace Splitter_UI.Services;
|
|
||||||
|
|
||||||
public class SingleThreadedDetector<T>(IObjectDetector _detector) : IObjectDetector
|
public class SingleThreadedDetector<T>(IObjectDetector _detector) : IObjectDetector
|
||||||
where T : IObjectDetector
|
where T : IObjectDetector
|
||||||
|
|||||||
@ -2,7 +2,6 @@
|
|||||||
using Avalonia;
|
using Avalonia;
|
||||||
using Avalonia.Media.Imaging;
|
using Avalonia.Media.Imaging;
|
||||||
using Avalonia.Platform;
|
using Avalonia.Platform;
|
||||||
using splitter.probe;
|
|
||||||
|
|
||||||
namespace Splitter_UI.Services;
|
namespace Splitter_UI.Services;
|
||||||
|
|
||||||
|
|||||||
@ -16,11 +16,6 @@ public partial class InspectorPaneViewModel : ObservableObject
|
|||||||
"face", "body", "none"
|
"face", "body", "none"
|
||||||
];
|
];
|
||||||
|
|
||||||
public List<int> RotationAngles =>
|
|
||||||
[
|
|
||||||
0, 90, 180, 270
|
|
||||||
];
|
|
||||||
|
|
||||||
[RelayCommand]
|
[RelayCommand]
|
||||||
private void ApplyOverrides()
|
private void ApplyOverrides()
|
||||||
{
|
{
|
||||||
|
|||||||
@ -5,9 +5,6 @@ using Avalonia.Media.Imaging;
|
|||||||
using Avalonia.Threading;
|
using Avalonia.Threading;
|
||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
using CommunityToolkit.Mvvm.Input;
|
using CommunityToolkit.Mvvm.Input;
|
||||||
using splitter.algo;
|
|
||||||
using splitter.probe;
|
|
||||||
using splitter.tui;
|
|
||||||
|
|
||||||
namespace Splitter_UI.ViewModels;
|
namespace Splitter_UI.ViewModels;
|
||||||
|
|
||||||
@ -19,7 +16,6 @@ public partial class JobViewModel : ObservableObject
|
|||||||
[ObservableProperty] private PreviewData? _preview = new(null, [], null, new(0.5f, 0.5f));
|
[ObservableProperty] private PreviewData? _preview = new(null, [], null, new(0.5f, 0.5f));
|
||||||
[ObservableProperty] private ProgressInfo? _progress;
|
[ObservableProperty] private ProgressInfo? _progress;
|
||||||
[ObservableProperty] private Bitmap? _thumbnail;
|
[ObservableProperty] private Bitmap? _thumbnail;
|
||||||
[ObservableProperty] private string _suggestedAction = "";
|
|
||||||
[ObservableProperty] private double _sliderLiveValue;
|
[ObservableProperty] private double _sliderLiveValue;
|
||||||
[ObservableProperty] private double _positionSeconds;
|
[ObservableProperty] private double _positionSeconds;
|
||||||
|
|
||||||
@ -217,6 +213,13 @@ public partial class JobViewModel : ObservableObject
|
|||||||
entry.PropertyChanged += OnParameterChanged;
|
entry.PropertyChanged += OnParameterChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PropertyChanged += (sender, e) =>
|
||||||
|
{
|
||||||
|
if (e.PropertyName == nameof(Probe))
|
||||||
|
{
|
||||||
|
OnPropertyChanged(nameof(DurationSeconds));
|
||||||
|
}
|
||||||
|
};
|
||||||
ParametersList.CollectionChanged += OnParametersCollectionChanged;
|
ParametersList.CollectionChanged += OnParametersCollectionChanged;
|
||||||
|
|
||||||
StepForwardCommand = new RelayCommand(StepForward);
|
StepForwardCommand = new RelayCommand(StepForward);
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
using splitter.algo;
|
|
||||||
|
|
||||||
namespace Splitter_UI.ViewModels;
|
namespace Splitter_UI.ViewModels;
|
||||||
|
|
||||||
|
|||||||
@ -82,7 +82,7 @@
|
|||||||
VerticalAlignment="Center"/>
|
VerticalAlignment="Center"/>
|
||||||
|
|
||||||
<TextBlock FontFamily="{StaticResource FontAwesome}"
|
<TextBlock FontFamily="{StaticResource FontAwesome}"
|
||||||
Text="{Binding SuggestedAction, Converter={StaticResource ActionToIconConverter}}"
|
Text="{Binding Rotate, Converter={StaticResource ActionToIconConverter}}"
|
||||||
FontSize="12"
|
FontSize="12"
|
||||||
HorizontalAlignment="Right"
|
HorizontalAlignment="Right"
|
||||||
Foreground="LimeGreen"/>
|
Foreground="LimeGreen"/>
|
||||||
|
|||||||
@ -1,5 +1,3 @@
|
|||||||
using Avalonia.Controls;
|
|
||||||
|
|
||||||
namespace Splitter_UI.Views;
|
namespace Splitter_UI.Views;
|
||||||
|
|
||||||
public partial class MainWindow : Avalonia.Controls.Window
|
public partial class MainWindow : Avalonia.Controls.Window
|
||||||
|
|||||||
@ -4,7 +4,6 @@ using Avalonia.Controls;
|
|||||||
using Avalonia.Input;
|
using Avalonia.Input;
|
||||||
using Avalonia.Media;
|
using Avalonia.Media;
|
||||||
using Avalonia.Threading;
|
using Avalonia.Threading;
|
||||||
using splitter.algo;
|
|
||||||
|
|
||||||
namespace Splitter_UI.Views;
|
namespace Splitter_UI.Views;
|
||||||
|
|
||||||
|
|||||||
@ -14,7 +14,7 @@
|
|||||||
Preview="{Binding Preview}"
|
Preview="{Binding Preview}"
|
||||||
Sar="{Binding Sar}"
|
Sar="{Binding Sar}"
|
||||||
RotateAngle="{Binding Rotate}"
|
RotateAngle="{Binding Rotate}"
|
||||||
GravitateTo="{Binding GravitateTo}"/>
|
GravitateTo="{Binding GravitateTo, Mode=TwoWay}"/>
|
||||||
|
|
||||||
<Grid Grid.Row="1"
|
<Grid Grid.Row="1"
|
||||||
ColumnDefinitions="Auto,*,Auto"
|
ColumnDefinitions="Auto,*,Auto"
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using splitter.algo;
|
|
||||||
using splitter.util;
|
using splitter.util;
|
||||||
|
|
||||||
namespace splitter;
|
namespace splitter;
|
||||||
|
|||||||
@ -1,7 +1,5 @@
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using splitter.algo;
|
|
||||||
using splitter.tui;
|
|
||||||
|
|
||||||
namespace splitter;
|
namespace splitter;
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using splitter.algo;
|
|
||||||
|
|
||||||
namespace splitter;
|
namespace splitter;
|
||||||
|
|
||||||
|
|||||||
@ -1,9 +1,6 @@
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using OpenCvSharp;
|
|
||||||
using splitter.algo;
|
|
||||||
using splitter.tui;
|
|
||||||
|
|
||||||
namespace splitter;
|
namespace splitter;
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,4 @@
|
|||||||
using OpenCvSharp;
|
namespace splitter.algo;
|
||||||
|
|
||||||
namespace splitter.algo;
|
|
||||||
|
|
||||||
public enum TrackState
|
public enum TrackState
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1,6 +1,4 @@
|
|||||||
using OpenCvSharp;
|
namespace splitter.algo;
|
||||||
|
|
||||||
namespace splitter.algo;
|
|
||||||
|
|
||||||
public interface IObjectDetector : IDisposable
|
public interface IObjectDetector : IDisposable
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1,6 +1,4 @@
|
|||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using OpenCvSharp;
|
|
||||||
using splitter.tui;
|
|
||||||
using UltraFaceDotNet;
|
using UltraFaceDotNet;
|
||||||
|
|
||||||
namespace splitter.algo;
|
namespace splitter.algo;
|
||||||
|
|||||||
@ -1,8 +1,6 @@
|
|||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using Microsoft.ML.OnnxRuntime;
|
using Microsoft.ML.OnnxRuntime;
|
||||||
using Microsoft.ML.OnnxRuntime.Tensors;
|
using Microsoft.ML.OnnxRuntime.Tensors;
|
||||||
using OpenCvSharp;
|
|
||||||
using splitter.tui;
|
|
||||||
|
|
||||||
namespace splitter.algo;
|
namespace splitter.algo;
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,4 @@
|
|||||||
using System;
|
using System.Text.Json.Serialization;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Text;
|
|
||||||
using System.Text.Json.Serialization;
|
|
||||||
|
|
||||||
namespace splitter.probe;
|
namespace splitter.probe;
|
||||||
|
|
||||||
|
|||||||
@ -1,9 +1,4 @@
|
|||||||
using System;
|
namespace splitter.probe;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Text;
|
|
||||||
using static splitter.probe.ProbeVideo;
|
|
||||||
|
|
||||||
namespace splitter.probe;
|
|
||||||
|
|
||||||
public sealed class FfprobeResult
|
public sealed class FfprobeResult
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1,7 +1,4 @@
|
|||||||
using System;
|
using System.Text.Json.Serialization;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Text;
|
|
||||||
using System.Text.Json.Serialization;
|
|
||||||
|
|
||||||
namespace splitter.probe;
|
namespace splitter.probe;
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,4 @@
|
|||||||
using OpenCvSharp;
|
namespace splitter.probe;
|
||||||
|
|
||||||
namespace splitter.probe;
|
|
||||||
|
|
||||||
public sealed class FrameRotationDetector
|
public sealed class FrameRotationDetector
|
||||||
{
|
{
|
||||||
|
|||||||
@ -2,7 +2,6 @@
|
|||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
using splitter.algo;
|
|
||||||
|
|
||||||
namespace splitter.probe;
|
namespace splitter.probe;
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,4 @@
|
|||||||
using OpenCvSharp;
|
namespace splitter.probe;
|
||||||
using splitter.algo;
|
|
||||||
|
|
||||||
namespace splitter.probe;
|
|
||||||
|
|
||||||
public record VideoInfo(
|
public record VideoInfo(
|
||||||
double Duration,
|
double Duration,
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
using OpenCvSharp;
|
using System.Diagnostics;
|
||||||
using System.Diagnostics;
|
|
||||||
|
|
||||||
namespace splitter.probe;
|
namespace splitter.probe;
|
||||||
|
|
||||||
|
|||||||
@ -2,9 +2,6 @@ using System.Collections.Concurrent;
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using Spectre.Console;
|
using Spectre.Console;
|
||||||
using splitter;
|
using splitter;
|
||||||
using splitter.algo;
|
|
||||||
using splitter.probe;
|
|
||||||
using splitter.tui;
|
|
||||||
|
|
||||||
static partial class Program
|
static partial class Program
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1,6 +1,4 @@
|
|||||||
using splitter;
|
using splitter;
|
||||||
using splitter.algo;
|
|
||||||
using splitter.probe;
|
|
||||||
|
|
||||||
public record SingleTask(
|
public record SingleTask(
|
||||||
SingleJob Job,
|
SingleJob Job,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user