Nicht wie hell das Bild ist, sondern wie viel davon schwarz
Gemessen wurde der Mittelwert über das ganze Bild, und daran scheiterte
die Abspannsuche wiederholt: weisse Schrift hebt den Mittelwert. Derselbe
Abspann misst 19, wenn wenig Schrift darin steht, und 37, wenn viel darin
steht — die Schwelle musste zwischen diesen Wert und die Handlung passen,
und der Abstand schrumpfte mit jeder Textzeile. Zweimal nachgezogen,
zweimal wieder getroffen.
Jellyfin zählt stattdessen Pixel, und das ist kein besserer Schwellenwert,
sondern ein besseres Merkmal. Nachgemessen an denselben erzeugten
Abspännen, durch dieselbe Kette wie im Betrieb:
Mittelwert Anteil dunkler Pixel
Handlung 128 0 %
Abspann, schriftreich 37 84 %
Abspann, schlank 19 87 %
dunkle Nachtszene 28 37 %
Schrift belegt ein bis zehn Prozent der Fläche; der Rest bleibt schwarz.
Der Anteil hängt deshalb nicht an der Schriftmenge, und der Abstand zur
Handlung ist nach beiden Seiten riesig.
`signalstats` weicht `blackframe=amount=0:threshold=24` — die Schwelle
für das einzelne Pixel über eine Reihe von Werten eingemessen: darunter
(16) fällt der Abspann selbst auf zehn Prozent ab, darüber (32) fängt die
Handlung an mitzuzählen. Die Ausgabe kommt über denselben
`metadata=print`-Weg wie vorher, nur unter einem anderen Schlüssel.
**Und die relative Schwelle fällt ersatzlos weg.** Sie war nötig, solange
der Mittelwert gemessen wurde: wie hell ein Abspann ist, hing am Film,
also musste sich die Schwelle am Film ausrichten. Der Pixelanteil eicht
sich selbst — `Abspannkante.Schwelle` und `Abspannregeln.Anteil` sind
gestrichen, und mit ihnen die Rechnerei um den Grundton.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
121ee62be9
commit
791c00dacc
@@ -13,9 +13,9 @@ public class BildabtasterLesenTests
|
||||
{
|
||||
var ausgabe = """
|
||||
frame:0 pts:30720 pts_time:2.5
|
||||
lavfi.signalstats.YAVG=125.065
|
||||
lavfi.blackframe.pblack=3
|
||||
frame:1 pts:61440 pts_time:5
|
||||
lavfi.signalstats.YAVG=18.4
|
||||
lavfi.blackframe.pblack=84
|
||||
|
||||
""";
|
||||
|
||||
@@ -23,8 +23,8 @@ public class BildabtasterLesenTests
|
||||
|
||||
Assert.That(proben, Is.EqualTo(new[]
|
||||
{
|
||||
new Bildprobe(62.5, 125.065),
|
||||
new Bildprobe(65, 18.4),
|
||||
new Bildprobe(62.5, 3),
|
||||
new Bildprobe(65, 84),
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ public class BildabtasterLesenTests
|
||||
[Test]
|
||||
public void Ein_Wert_ohne_Zeit_faellt_heraus()
|
||||
{
|
||||
Assert.That(Bildabtaster.Lesen("lavfi.signalstats.YAVG=18.4\n", 0), Is.Empty);
|
||||
Assert.That(Bildabtaster.Lesen("lavfi.blackframe.pblack=84\n", 0), Is.Empty);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -133,8 +133,8 @@ public class BildabtasterLaufTests
|
||||
var hell = Abspannkante.HellDavor(proben, grob!.Value, Abspannregeln.Vorgabe) ?? 0;
|
||||
var abtaster = Abtaster();
|
||||
var kante = await Abspannkante.VerfeinernAsync(
|
||||
hell, grob.Value, Abspannkante.Schwelle(proben, Abspannregeln.Vorgabe),
|
||||
stelle => abtaster.HelligkeitAsync(_datei, stelle));
|
||||
hell, grob.Value, Abspannregeln.Vorgabe.Mindestanteil,
|
||||
stelle => abtaster.DunkelanteilAsync(_datei, stelle));
|
||||
|
||||
Assert.That(kante, Is.EqualTo(90).Within(4),
|
||||
"erzeugt wurde der Übergang bei genau 90 Sekunden");
|
||||
@@ -153,39 +153,36 @@ public class BildabtasterLaufTests
|
||||
///
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// <b>Hier stand der Fehler, und hier wurde er sichtbar.</b> Diese
|
||||
/// Prüfung verlangte früher, dass der Abspann unter der festen
|
||||
/// Schwelle von 35 liegt — mit dem schmalen Balken von damals lag er
|
||||
/// bei 18, und alles schien zu stimmen. Mit realistischer
|
||||
/// Schriftdichte misst dieselbe Stelle <b>40</b>. Die feste Schwelle
|
||||
/// hätte diesen Abspann also für Handlung gehalten, und genau das
|
||||
/// geschah im Bestand.
|
||||
/// <b>Hier wurde der alte Fehler sichtbar.</b> Gemessen wurde lange
|
||||
/// der Mittelwert der Helligkeit; diese Prüfung verlangte, dass der
|
||||
/// Abspann unter einer festen Schwelle von 35 liegt. Mit dem schmalen
|
||||
/// Balken von damals lag er bei 18, und alles schien zu stimmen — mit
|
||||
/// realistischer Schriftdichte bei 40. Die feste Schwelle hielt
|
||||
/// diesen Abspann also für Handlung, und genau das geschah im
|
||||
/// Bestand.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Gemessen wird deshalb gegen die Schwelle, die der Film selbst
|
||||
/// vorgibt — und die liegt hier zwischen 40 und der Handlung.
|
||||
/// Nach Pixelanteilen stellt sich die Frage nicht mehr: gemessen
|
||||
/// werden hier rund 90 Prozent im Abspann gegen null in der Handlung.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
[Test]
|
||||
public async Task Eine_Sekunde_im_Abspann_liegt_unter_der_Schwelle()
|
||||
public async Task Eine_Sekunde_im_Abspann_ist_fast_ganz_dunkel()
|
||||
{
|
||||
var proben = await Abtaster().UeberblickAsync(_datei, ab: 30, dauer: 120);
|
||||
var schwelle = Abspannkante.Schwelle(proben, Abspannregeln.Vorgabe);
|
||||
var noetig = Abspannregeln.Vorgabe.Mindestanteil;
|
||||
|
||||
var dunkel = await Abtaster().HelligkeitAsync(_datei, bei: 120);
|
||||
var hell = await Abtaster().HelligkeitAsync(_datei, bei: 40);
|
||||
var dunkel = await Abtaster().DunkelanteilAsync(_datei, bei: 120);
|
||||
var hell = await Abtaster().DunkelanteilAsync(_datei, bei: 40);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(dunkel, Is.Not.Null.And.LessThan(schwelle));
|
||||
Assert.That(hell, Is.Not.Null.And.GreaterThan(schwelle));
|
||||
Assert.That(dunkel, Is.GreaterThan(Abspannregeln.Vorgabe.Dunkelschwelle),
|
||||
"dieser Abspann ist heller als der alte feste Wert — darum ging es");
|
||||
Assert.That(dunkel, Is.Not.Null.And.GreaterThan(noetig));
|
||||
Assert.That(hell, Is.Not.Null.And.LessThan(noetig));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Dieselbe Helligkeit, gleich welche Bittiefe die Datei hat.</summary>
|
||||
/// <summary>Derselbe Dunkelanteil, gleich welche Bittiefe die Datei hat.</summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
@@ -251,8 +248,8 @@ public class BildabtasterBittiefeTests
|
||||
var abtaster = new Bildabtaster(
|
||||
FfmpegOptions.FromEnvironment(), NullLogger<Bildabtaster>.Instance);
|
||||
|
||||
var acht = await abtaster.HelligkeitAsync(Erzeugen("yuv420p"), bei: 2);
|
||||
var zehn = await abtaster.HelligkeitAsync(Erzeugen("yuv420p10le"), bei: 2);
|
||||
var acht = await abtaster.DunkelanteilAsync(Erzeugen("yuv420p"), bei: 2);
|
||||
var zehn = await abtaster.DunkelanteilAsync(Erzeugen("yuv420p10le"), bei: 2);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user