mirror of
https://github.com/n00mkrad/flowframes.git
synced 2026-09-01 19:51:28 +02:00
Improved alpha support
This commit is contained in:
@@ -16,7 +16,6 @@ namespace Flowframes
|
||||
{
|
||||
class FFmpegCommands
|
||||
{
|
||||
static string hdrFilter = @"-vf select=gte(n\,%frNum%),zscale=t=linear:npl=100,format=gbrpf32le,zscale=p=bt709,tonemap=tonemap=hable:desat=0,zscale=t=bt709:m=bt709:r=tv,format=yuv420p";
|
||||
static string divisionFilter = "\"pad=width=ceil(iw/2)*2:height=ceil(ih/2)*2:color=black@0\"";
|
||||
static string pngComprArg = "-compression_level 3";
|
||||
static string mpDecDef = "\"mpdecimate\"";
|
||||
@@ -44,7 +43,7 @@ namespace Flowframes
|
||||
string timecodeStr = timecodes ? $"-copyts -r {FrameOrder.timebase} -frame_pts true" : "-copyts -frame_pts true";
|
||||
string scnDetect = sceneDetect ? $"\"select='gt(scene,{Config.GetFloatString("scnDetectValue")})'\"" : "";
|
||||
string mpStr = deDupe ? ((Config.GetInt("mpdecimateMode") == 0) ? mpDecDef : mpDecAggr) : "";
|
||||
string filters = FormatUtils.ConcatStrings(new string[] { scnDetect, mpStr } );
|
||||
string filters = FormatUtils.ConcatStrings(new string[] { divisionFilter, scnDetect, mpStr } );
|
||||
string vf = filters.Length > 2 ? $"-vf {filters}" : "";
|
||||
string rateArg = (rate > 0) ? $" -r {rate.ToStringDot()}" : "";
|
||||
string pixFmt = alpha ? "-pix_fmt rgba" : "-pix_fmt rgb24"; // Use RGBA for GIF for alpha support
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Flowframes.IO
|
||||
{
|
||||
@@ -13,11 +10,7 @@ namespace Flowframes.IO
|
||||
public const string interpDir = "interp";
|
||||
public const string chunksDir = "vchunks";
|
||||
public const string scenesDir = "scenes";
|
||||
|
||||
public static void Init()
|
||||
{
|
||||
|
||||
}
|
||||
public const string alphaSuffix = "-a";
|
||||
|
||||
public static string GetVerPath()
|
||||
{
|
||||
4
Code/Forms/SettingsForm.Designer.cs
generated
4
Code/Forms/SettingsForm.Designer.cs
generated
@@ -513,9 +513,9 @@
|
||||
this.label25.Location = new System.Drawing.Point(10, 70);
|
||||
this.label25.Margin = new System.Windows.Forms.Padding(10, 10, 10, 7);
|
||||
this.label25.Name = "label25";
|
||||
this.label25.Size = new System.Drawing.Size(108, 13);
|
||||
this.label25.Size = new System.Drawing.Size(177, 13);
|
||||
this.label25.TabIndex = 76;
|
||||
this.label25.Text = "Enable Transparency";
|
||||
this.label25.Text = "Enable Transparency (Experimental)";
|
||||
//
|
||||
// keepSubs
|
||||
//
|
||||
|
||||
@@ -36,11 +36,45 @@ namespace Flowframes.Magick
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task ExtractAlpha (string inputDir, string outputDir, bool print = true, bool setProgress = true)
|
||||
public static async Task MakeBinary (string inputDir, string outputDir, bool print = true, bool setProgress = true)
|
||||
{
|
||||
try
|
||||
{
|
||||
var files = IOUtils.GetFilesSorted(inputDir);
|
||||
if (print) Logger.Log($"Processing alpha channel...");
|
||||
Directory.CreateDirectory(outputDir);
|
||||
Stopwatch sw = new Stopwatch();
|
||||
sw.Restart();
|
||||
int counter = 0;
|
||||
foreach (string file in files)
|
||||
{
|
||||
MagickImage img = new MagickImage(file);
|
||||
img.Format = MagickFormat.Png24;
|
||||
img.Quality = 10;
|
||||
img.Threshold(new Percentage(90));
|
||||
|
||||
string outPath = Path.Combine(outputDir, Path.GetFileName(file));
|
||||
img.Write(outPath);
|
||||
counter++;
|
||||
if (sw.ElapsedMilliseconds > 250)
|
||||
{
|
||||
if (setProgress)
|
||||
Program.mainForm.SetProgress((int)Math.Round(((float)counter / files.Length) * 100f));
|
||||
await Task.Delay(1);
|
||||
sw.Restart();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Log("ExtractAlpha Error: " + e.Message);
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task ExtractAlpha (string inputDir, string outputDir, bool print = true, bool setProgress = true, bool removeInputAlpha = true)
|
||||
{
|
||||
try
|
||||
{
|
||||
var files = IOUtils.GetFilesSorted(inputDir);
|
||||
if (print) Logger.Log($"Extracting alpha channel from images...");
|
||||
Directory.CreateDirectory(outputDir);
|
||||
@@ -49,16 +83,28 @@ namespace Flowframes.Magick
|
||||
int counter = 0;
|
||||
foreach (string file in files)
|
||||
{
|
||||
MagickImage img = new MagickImage(file);
|
||||
img.Format = MagickFormat.Png32;
|
||||
img.Quality = 10;
|
||||
MagickImage alphaImg = new MagickImage(file);
|
||||
|
||||
if (removeInputAlpha)
|
||||
{
|
||||
MagickImage rgbImg = alphaImg;
|
||||
rgbImg.Format = MagickFormat.Png24;
|
||||
rgbImg.Quality = 10;
|
||||
MagickImage bg = new MagickImage(MagickColors.Black, rgbImg.Width, rgbImg.Height);
|
||||
bg.Composite(rgbImg, CompositeOperator.Over);
|
||||
rgbImg = bg;
|
||||
rgbImg.Write(file);
|
||||
}
|
||||
|
||||
alphaImg.Format = MagickFormat.Png24;
|
||||
alphaImg.Quality = 10;
|
||||
|
||||
img.FloodFill(MagickColors.None, 0, 0); // Fill the image with a transparent background
|
||||
img.InverseOpaque(MagickColors.None, MagickColors.White); // Change all the pixels that are not transparent to white.
|
||||
img.ColorAlpha(MagickColors.Black); // Change the transparent pixels to black.
|
||||
alphaImg.FloodFill(MagickColors.None, 0, 0); // Fill the image with a transparent background
|
||||
alphaImg.InverseOpaque(MagickColors.None, MagickColors.White); // Change all the pixels that are not transparent to white.
|
||||
alphaImg.ColorAlpha(MagickColors.Black); // Change the transparent pixels to black.
|
||||
|
||||
string outPath = Path.Combine(outputDir, Path.GetFileName(file));
|
||||
img.Write(outPath);
|
||||
alphaImg.Write(outPath);
|
||||
counter++;
|
||||
if (sw.ElapsedMilliseconds > 250)
|
||||
{
|
||||
|
||||
@@ -86,7 +86,7 @@ namespace Flowframes
|
||||
|
||||
Program.mainForm.SetStatus("Extracting frames from video...");
|
||||
bool mpdecimate = Config.GetInt("dedupMode") == 2;
|
||||
await FFmpegCommands.VideoToFrames(inPath, outPath, alpha, current.inFps, mpdecimate, false, await Utils.GetOutputResolution(inPath, true), false);
|
||||
await FFmpegCommands.VideoToFrames(inPath, outPath, alpha, current.inFps, mpdecimate, false, await Utils.GetOutputResolution(inPath, true, true), false);
|
||||
|
||||
if (mpdecimate)
|
||||
{
|
||||
|
||||
@@ -327,9 +327,6 @@ namespace Flowframes.Main
|
||||
{
|
||||
if (videoPath == null || !IOUtils.IsFileValid(videoPath))
|
||||
return false;
|
||||
// string ext = Path.GetExtension(videoPath).ToLower();
|
||||
// if (!Formats.supported.Contains(ext))
|
||||
// return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -340,13 +337,13 @@ namespace Flowframes.Main
|
||||
Logger.Log("Message: " + msg, true);
|
||||
}
|
||||
|
||||
public static async Task<Size> GetOutputResolution (string inputPath, bool print)
|
||||
public static async Task<Size> GetOutputResolution (string inputPath, bool print, bool returnZeroIfUnchanged = false)
|
||||
{
|
||||
Size resolution = await IOUtils.GetVideoOrFramesRes(inputPath);
|
||||
return GetOutputResolution(resolution, print);
|
||||
return GetOutputResolution(resolution, print, returnZeroIfUnchanged);
|
||||
}
|
||||
|
||||
public static Size GetOutputResolution(Size inputRes, bool print = false)
|
||||
public static Size GetOutputResolution(Size inputRes, bool print = false, bool returnZeroIfUnchanged = false)
|
||||
{
|
||||
int maxHeight = RoundDiv2(Config.GetInt("maxVidHeight"));
|
||||
if (inputRes.Height > maxHeight)
|
||||
@@ -360,7 +357,11 @@ namespace Flowframes.Main
|
||||
}
|
||||
else
|
||||
{
|
||||
return new Size(RoundDiv2(inputRes.Width), RoundDiv2(inputRes.Height));
|
||||
//return new Size(RoundDiv2(inputRes.Width), RoundDiv2(inputRes.Height));
|
||||
if (returnZeroIfUnchanged)
|
||||
return new Size();
|
||||
else
|
||||
return inputRes;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ using Flowframes.UI;
|
||||
using Flowframes.Main;
|
||||
using Flowframes.Data;
|
||||
using Flowframes.MiscUtils;
|
||||
using Flowframes.Magick;
|
||||
|
||||
namespace Flowframes
|
||||
{
|
||||
@@ -76,6 +77,17 @@ namespace Flowframes
|
||||
|
||||
await Task.Delay(500);
|
||||
}
|
||||
|
||||
if (!Interpolate.canceled && Interpolate.current.alpha)
|
||||
{
|
||||
Logger.Log("Processing alpha...");
|
||||
string rgbInterpDir = Path.Combine(Interpolate.current.tempFolder, Paths.interpDir);
|
||||
string alphaInterpDir = Path.Combine(Interpolate.current.tempFolder, Paths.interpDir + Paths.alphaSuffix);
|
||||
if (!Directory.Exists(alphaInterpDir)) return;
|
||||
if (Interpolate.current.outMode == Interpolate.OutMode.VidGif)
|
||||
await Converter.MakeBinary(alphaInterpDir, alphaInterpDir, false); // Apply threshold if output has binary alpha
|
||||
await FFmpegCommands.MergeAlphaIntoRgb(rgbInterpDir, Padding.interpFrames, alphaInterpDir, Padding.interpFrames);
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task RunRifeCuda(string framesPath, int interpFactor, string mdl)
|
||||
@@ -95,17 +107,10 @@ namespace Flowframes
|
||||
{
|
||||
InterpolateUtils.progressPaused = true;
|
||||
Logger.Log("Interpolating alpha channel...");
|
||||
await RunRifeCudaProcess(framesPath + "-a", Paths.interpDir + "-a", script, interpFactor, mdl);
|
||||
await RunRifeCudaProcess(framesPath + Paths.alphaSuffix, Paths.interpDir + Paths.alphaSuffix, script, interpFactor, mdl);
|
||||
}
|
||||
|
||||
await AiFinished("RIFE");
|
||||
|
||||
if (!Interpolate.canceled && Interpolate.current.alpha)
|
||||
{
|
||||
Logger.Log("Processing alpha...");
|
||||
string rgbInterpDir = Path.Combine(Interpolate.current.tempFolder, Paths.interpDir);
|
||||
await FFmpegCommands.MergeAlphaIntoRgb(rgbInterpDir, Padding.interpFrames, rgbInterpDir + "-a", Padding.interpFrames);
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task RunRifeCudaProcess (string inPath, string outDir, string script, int interpFactor, string mdl)
|
||||
|
||||
Reference in New Issue
Block a user