mirror of
https://github.com/unclshura/splitter.git
synced 2026-06-21 16:12: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)
|
||||
{
|
||||
return value switch
|
||||
{
|
||||
"crop" => "\uf125", // FA7 crop
|
||||
"rotate" => "\uf2f1", // FA7 rotate
|
||||
_ => null
|
||||
};
|
||||
if (value == null)
|
||||
return null;
|
||||
|
||||
var p = System.Convert.ToInt32(value);
|
||||
|
||||
return p == 0
|
||||
? "\uf125" // FA7 crop
|
||||
: "\uf2f1" // FA7 rotate
|
||||
;
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
|
||||
@ -1,8 +1,6 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Media;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using splitter.algo;
|
||||
using splitter.tui;
|
||||
|
||||
namespace Splitter_UI;
|
||||
|
||||
|
||||
@ -1,6 +1,4 @@
|
||||
using NcnnDotNet.Layers;
|
||||
using OpenCvSharp;
|
||||
using splitter.tui;
|
||||
using OpenCvSharp.Dnn;
|
||||
|
||||
namespace Splitter_UI.Services;
|
||||
|
||||
@ -15,19 +13,63 @@ public sealed class AutoDecisionService(IThumbnailService _thumbnails, IFileProb
|
||||
{
|
||||
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.Thumbnail = await _thumbnails.CreateThumbnailAsync(job.InputFile, job.Probe, rotateDegree: job.Rotate);
|
||||
|
||||
var sampler = new VideoRotationSampler(null);
|
||||
job.Rotate = await sampler.DetectRotationAsync(job.InputFile, job.Probe.Duration);
|
||||
job.SuggestedAction = job.Rotate == 0 ? "crop" : "rotate";
|
||||
|
||||
if (job.SuggestedAction == "crop")
|
||||
if (job.Probe.Width > job.Probe.Height)
|
||||
{
|
||||
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)
|
||||
{
|
||||
_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 Avalonia;
|
||||
using Avalonia.Media.Imaging;
|
||||
using OpenCvSharp;
|
||||
|
||||
namespace Splitter_UI.Services;
|
||||
|
||||
|
||||
@ -1,7 +1,4 @@
|
||||
using OpenCvSharp;
|
||||
using splitter.algo;
|
||||
|
||||
namespace Splitter_UI.Services;
|
||||
namespace Splitter_UI.Services;
|
||||
|
||||
internal class DummyDetector : IObjectDetector
|
||||
{
|
||||
|
||||
@ -1,6 +1,4 @@
|
||||
using splitter.probe;
|
||||
|
||||
namespace Splitter_UI.Services;
|
||||
namespace Splitter_UI.Services;
|
||||
|
||||
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
|
||||
{
|
||||
|
||||
@ -1,6 +1,4 @@
|
||||
using splitter.probe;
|
||||
|
||||
namespace Splitter_UI.Services;
|
||||
namespace Splitter_UI.Services;
|
||||
|
||||
public interface IFileProbeService
|
||||
{
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
using Avalonia.Media.Imaging;
|
||||
using splitter.probe;
|
||||
|
||||
namespace Splitter_UI.Services;
|
||||
|
||||
|
||||
@ -1,7 +1,4 @@
|
||||
using OpenCvSharp;
|
||||
using splitter.algo;
|
||||
|
||||
namespace Splitter_UI.Services;
|
||||
namespace Splitter_UI.Services;
|
||||
|
||||
public class SingleThreadedDetector<T>(IObjectDetector _detector) : IObjectDetector
|
||||
where T : IObjectDetector
|
||||
|
||||
@ -2,7 +2,6 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Media.Imaging;
|
||||
using Avalonia.Platform;
|
||||
using splitter.probe;
|
||||
|
||||
namespace Splitter_UI.Services;
|
||||
|
||||
|
||||
@ -16,11 +16,6 @@ public partial class InspectorPaneViewModel : ObservableObject
|
||||
"face", "body", "none"
|
||||
];
|
||||
|
||||
public List<int> RotationAngles =>
|
||||
[
|
||||
0, 90, 180, 270
|
||||
];
|
||||
|
||||
[RelayCommand]
|
||||
private void ApplyOverrides()
|
||||
{
|
||||
|
||||
@ -5,9 +5,6 @@ using Avalonia.Media.Imaging;
|
||||
using Avalonia.Threading;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using splitter.algo;
|
||||
using splitter.probe;
|
||||
using splitter.tui;
|
||||
|
||||
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 ProgressInfo? _progress;
|
||||
[ObservableProperty] private Bitmap? _thumbnail;
|
||||
[ObservableProperty] private string _suggestedAction = "";
|
||||
[ObservableProperty] private double _sliderLiveValue;
|
||||
[ObservableProperty] private double _positionSeconds;
|
||||
|
||||
@ -217,6 +213,13 @@ public partial class JobViewModel : ObservableObject
|
||||
entry.PropertyChanged += OnParameterChanged;
|
||||
}
|
||||
|
||||
PropertyChanged += (sender, e) =>
|
||||
{
|
||||
if (e.PropertyName == nameof(Probe))
|
||||
{
|
||||
OnPropertyChanged(nameof(DurationSeconds));
|
||||
}
|
||||
};
|
||||
ParametersList.CollectionChanged += OnParametersCollectionChanged;
|
||||
|
||||
StepForwardCommand = new RelayCommand(StepForward);
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
using System.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using splitter.algo;
|
||||
|
||||
namespace Splitter_UI.ViewModels;
|
||||
|
||||
|
||||
@ -82,7 +82,7 @@
|
||||
VerticalAlignment="Center"/>
|
||||
|
||||
<TextBlock FontFamily="{StaticResource FontAwesome}"
|
||||
Text="{Binding SuggestedAction, Converter={StaticResource ActionToIconConverter}}"
|
||||
Text="{Binding Rotate, Converter={StaticResource ActionToIconConverter}}"
|
||||
FontSize="12"
|
||||
HorizontalAlignment="Right"
|
||||
Foreground="LimeGreen"/>
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
using Avalonia.Controls;
|
||||
|
||||
namespace Splitter_UI.Views;
|
||||
|
||||
public partial class MainWindow : Avalonia.Controls.Window
|
||||
|
||||
@ -4,7 +4,6 @@ using Avalonia.Controls;
|
||||
using Avalonia.Input;
|
||||
using Avalonia.Media;
|
||||
using Avalonia.Threading;
|
||||
using splitter.algo;
|
||||
|
||||
namespace Splitter_UI.Views;
|
||||
|
||||
|
||||
@ -14,7 +14,7 @@
|
||||
Preview="{Binding Preview}"
|
||||
Sar="{Binding Sar}"
|
||||
RotateAngle="{Binding Rotate}"
|
||||
GravitateTo="{Binding GravitateTo}"/>
|
||||
GravitateTo="{Binding GravitateTo, Mode=TwoWay}"/>
|
||||
|
||||
<Grid Grid.Row="1"
|
||||
ColumnDefinitions="Auto,*,Auto"
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
using System.Globalization;
|
||||
using splitter.algo;
|
||||
using splitter.util;
|
||||
|
||||
namespace splitter;
|
||||
|
||||
@ -1,7 +1,5 @@
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using splitter.algo;
|
||||
using splitter.tui;
|
||||
|
||||
namespace splitter;
|
||||
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
using System.Globalization;
|
||||
using splitter.algo;
|
||||
|
||||
namespace splitter;
|
||||
|
||||
|
||||
@ -1,9 +1,6 @@
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.Runtime.InteropServices;
|
||||
using OpenCvSharp;
|
||||
using splitter.algo;
|
||||
using splitter.tui;
|
||||
|
||||
namespace splitter;
|
||||
|
||||
|
||||
@ -1,6 +1,4 @@
|
||||
using OpenCvSharp;
|
||||
|
||||
namespace splitter.algo;
|
||||
namespace splitter.algo;
|
||||
|
||||
public enum TrackState
|
||||
{
|
||||
|
||||
@ -1,6 +1,4 @@
|
||||
using OpenCvSharp;
|
||||
|
||||
namespace splitter.algo;
|
||||
namespace splitter.algo;
|
||||
|
||||
public interface IObjectDetector : IDisposable
|
||||
{
|
||||
|
||||
@ -1,6 +1,4 @@
|
||||
using System.Runtime.InteropServices;
|
||||
using OpenCvSharp;
|
||||
using splitter.tui;
|
||||
using UltraFaceDotNet;
|
||||
|
||||
namespace splitter.algo;
|
||||
|
||||
@ -1,8 +1,6 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
using Microsoft.ML.OnnxRuntime;
|
||||
using Microsoft.ML.OnnxRuntime.Tensors;
|
||||
using OpenCvSharp;
|
||||
using splitter.tui;
|
||||
|
||||
namespace splitter.algo;
|
||||
|
||||
|
||||
@ -1,7 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace splitter.probe;
|
||||
|
||||
|
||||
@ -1,9 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using static splitter.probe.ProbeVideo;
|
||||
|
||||
namespace splitter.probe;
|
||||
namespace splitter.probe;
|
||||
|
||||
public sealed class FfprobeResult
|
||||
{
|
||||
|
||||
@ -1,7 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace splitter.probe;
|
||||
|
||||
|
||||
@ -1,6 +1,4 @@
|
||||
using OpenCvSharp;
|
||||
|
||||
namespace splitter.probe;
|
||||
namespace splitter.probe;
|
||||
|
||||
public sealed class FrameRotationDetector
|
||||
{
|
||||
|
||||
@ -2,7 +2,6 @@
|
||||
using System.Globalization;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using splitter.algo;
|
||||
|
||||
namespace splitter.probe;
|
||||
|
||||
|
||||
@ -1,7 +1,4 @@
|
||||
using OpenCvSharp;
|
||||
using splitter.algo;
|
||||
|
||||
namespace splitter.probe;
|
||||
namespace splitter.probe;
|
||||
|
||||
public record VideoInfo(
|
||||
double Duration,
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
using OpenCvSharp;
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace splitter.probe;
|
||||
|
||||
|
||||
@ -2,9 +2,6 @@ using System.Collections.Concurrent;
|
||||
using System.Diagnostics;
|
||||
using Spectre.Console;
|
||||
using splitter;
|
||||
using splitter.algo;
|
||||
using splitter.probe;
|
||||
using splitter.tui;
|
||||
|
||||
static partial class Program
|
||||
{
|
||||
|
||||
@ -1,6 +1,4 @@
|
||||
using splitter;
|
||||
using splitter.algo;
|
||||
using splitter.probe;
|
||||
|
||||
public record SingleTask(
|
||||
SingleJob Job,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user