Finish rewriting Aard

This commit is contained in:
Tamius Han 2025-10-13 17:35:37 +02:00
parent 888e48eb5b
commit ddffbe92a0
9 changed files with 376 additions and 1863 deletions

2
package-lock.json generated
View File

@ -1,6 +1,6 @@
{
"name": "ultrawidify",
"version": "6.3.94",
"version": "6.3.97",
"lockfileVersion": 1,
"requires": true,
"dependencies": {

View File

@ -1,6 +1,6 @@
{
"name": "ultrawidify",
"version": "6.3.94",
"version": "6.3.97",
"description": "Aspect ratio fixer for youtube and other sites, with automatic aspect ratio detection. Supports ultrawide and other ratios.",
"author": "Tamius Han <tamius.han@gmail.com>",
"scripts": {

View File

@ -76,14 +76,13 @@ export interface AardSubtitleScanOptions {
// should be somewhere between 0.1-0.3 in order for subtitle scan to
// work properly.
maxValidLetter: number, // if letter is longer than this, something's off.
maxValidImage: number,
subtitleSubpixelThresholdOn: number,
subtitleSubpixelThresholdOff: number,
minImageSegment
minDetections: number,
minImageLineDetections: number,
maxPotentialSubtitleMisalignment: number, // how many pixels off-center can "potential subtitle" be
refiningScanSpacing: number, // must be base-2
refiningScanInitialIterations: number,
@ -153,36 +152,16 @@ export interface AardSettings {
// pls deprecate and move things used
edgeDetection: {
slopeTestWidth: number,
gradientTestSamples: number, // we check this many pixels below (or above) the suspected edge to check for gradient
gradientTestBlackThreshold: number, // if pixel in test sample is brighter than that, we aren't looking at gradient
gradientTestDeltaThreshold: number, // if delta between two adjacent pixels in gradient test exceeds this, it's not gradient
gradientTestMinDelta: number, // if last pixels of the test sample is less than this brighter than the first -> not gradient
gradientThreshold: number, // if more than this percentage (0-1) is detected as gradient, we mark edge as gradient
gradientTestMinDelta: number, // if difference between test row and before row is MORE than this -> not gradient
gradientTestMinDeltaAfter: number, // if difference between test row and after row is LESS than this -> not gradient
gradientTestMaxDeltaAfter: number, // if difference between test row and after row is MORE than this -> not gradient
maxLetterboxOffset: number, // Upper and lower letterbox can be different by this many (% of height)
thresholds: {
edgeDetectionLimit: number, // during scanning of the edge, quit after edge gets detected at this many points
minQualitySingleEdge: number, // At least one of the detected must reach this quality
minQualitySecondEdge: number, // The other edge must reach this quality (must be smaller or equal to single edge quality)
}
maxLetterboxOffset: number, // Upper and lower letterbox can be different by this many (% of height)
// Previous iteration variables VVVV
sampleWidth: number, // we take a sample this wide for edge detection
detectionThreshold: number, // sample needs to have this many non-black pixels to be a valid edge
confirmationThreshold: number, //
singleSideConfirmationThreshold: number, // we need this much edges (out of all samples, not just edges) in order
// to confirm an edge in case there's no edges on top or bottom (other
// than logo, of course)
logoThreshold: number, // if edge candidate sits with count greater than this*all_samples, it can't be logo
// or watermark.
edgeTolerancePx?: number, // we check for black edge violation this far from detection point
edgeTolerancePercent?: number, // we check for black edge detection this % of height from detection point. unused
middleIgnoredArea: number, // we ignore this % of canvas height towards edges while detecting aspect ratios
minColsForSearch: number, // if we hit the edge of blackbars for all but this many columns (%-wise), we don't
// continue with search. It's pointless, because black edge is higher/lower than we
// are now. (NOTE: keep this less than 1 in case we implement logo detection)
edgeMismatchTolerancePx: number,// corners and center are considered equal if they differ by at most this many px
minValidImage: number, // if more than this % (0-1) of row is image, we confirm image regardless of other criteria except gradient
maxEdgeSegments: number, // if edge has more than this many segments, we consider it unreliable
minEdgeSegmentSize: number,
averageEdgeThreshold: number, // average edge must be this many px
},
letterboxOrientationScan: {

View File

@ -261,9 +261,11 @@ const ExtensionConfPatch = Object.freeze([
}
},
{
forVersion: '6.3.94',
forVersion: '6.3.97',
updateFn: (userOptions: SettingsInterface, defaultOptions: SettingsInterface) => {
userOptions.arDetect.letterboxOrientationScan = defaultOptions.arDetect.letterboxOrientationScan;
userOptions.arDetect.edgeDetection = defaultOptions.arDetect.edgeDetection;
userOptions.arDetect.subtitles = defaultOptions.arDetect.subtitles;
}
}

View File

@ -35,19 +35,20 @@ const ExtensionConf: SettingsInterface = {
},
subtitles: {
subtitleCropMode: AardSubtitleCropMode.DisableScan,
subtitleCropMode: AardSubtitleCropMode.ResetAR,
resumeAfter: 5000,
scanSpacing: 5,
scanMargin: 0.25,
maxValidLetter: 24,
maxValidImage: 0.33,
subtitleSubpixelThresholdOff: 8,
subtitleSubpixelThresholdOn: 192,
minDetections: 8,
minImageLineDetections: 16,
minImageLineDetections: 8,
refiningScanSpacing: 8,
refiningScanInitialIterations: 12,
maxPotentialSubtitleMisalignment: 32,
},
earlyStopOptions: {
@ -99,36 +100,17 @@ const ExtensionConf: SettingsInterface = {
staticRows: 9, // forms grid with staticSampleCols. Determined in the same way. For black frame checks
},
edgeDetection: {
slopeTestWidth: 8,
gradientTestSamples: 8,
gradientTestBlackThreshold: 16,
gradientTestDeltaThreshold: 32,
gradientTestMinDelta: 8,
maxLetterboxOffset: 0.05,
thresholds: {
edgeDetectionLimit: 12,
minQualitySingleEdge: 6,
minQualitySecondEdge: 3,
},
gradientThreshold: 0.5, // if more than this percentage (0-1) is detected as gradient, we mark edge as gradient
gradientTestMinDelta: 8, // if difference between test row and before row is MORE than this -> not gradient
gradientTestMinDeltaAfter: 2, // if difference between test row and after row is LESS than this -> not gradient
gradientTestMaxDeltaAfter: 12, // if difference between test row and after row is MORE than this -> not gradient
maxLetterboxOffset: 0.1,
sampleWidth: 8, // we take a sample this wide for edge detection
detectionThreshold: 4, // sample needs to have this many non-black pixels to be a valid edge
confirmationThreshold: 1, //
singleSideConfirmationThreshold: 3, // we need this much edges (out of all samples, not just edges) in order
// to confirm an edge in case there's no edges on top or bottom (other
// than logo, of course)
logoThreshold: 0.15, // if edge candidate sits with count greater than this*all_samples, it can't be logo
// or watermark.
edgeTolerancePx: 1, // we check for black edge violation this far from detection point
edgeTolerancePercent: null, // we check for black edge detection this % of height from detection point. unused
middleIgnoredArea: 0.2, // we ignore this % of canvas height towards edges while detecting aspect ratios
minColsForSearch: 0.5, // if we hit the edge of blackbars for all but this many columns (%-wise), we don't
// continue with search. It's pointless, because black edge is higher/lower than we
// are now. (NOTE: keep this less than 1 in case we implement logo detection)
edgeMismatchTolerancePx: 3, // corners and center are considered equal if they differ by at most this many px
minValidImage: 0.7, // if more than this % (0-1) of row is image, we confirm image regardless of other criteria except gradient
maxEdgeSegments: 8, // if edge has more than this many segments, we consider it unreliable
minEdgeSegmentSize: 2,
averageEdgeThreshold: 16, // average(ish) edge must be this many px
},
pillarTest: {
ignoreThinPillarsPx: 5, // ignore pillars that are less than this many pixels thick.

File diff suppressed because it is too large Load Diff

View File

@ -120,9 +120,9 @@ export class GlDebugCanvas extends GlCanvas {
0.4, 0.4, 1.0, // 9 - edge scan hit
0.2, 0.4, 0.6, // 10 - slope test ok
1.0, 0.0, 0.0, // 11 - slope test fail
0.3, 0.3, 0.1, // 12 - first subtitle off pixel
1.0, 0.5, 0.0, // 13 - first subtitle on pixel
1.0, 1.0, 0.0, // 14 - pixel subtitle — no threshold
0.1, 0.1, 0.3, // 12 - first subtitle off pixel
1.0, 1.6, 0.0, // 13 - first subtitle on pixel
7.0, 0.2, 0.0, // 14 - pixel subtitle — no threshold
1.0, 0.0, 0.0, // 15 - letterbox scan image detection
];
private debugColors2 = [

View File

@ -8,7 +8,8 @@ export interface AardTestResult_SubtitleRegion {
firstSubtitle: number,
lastSubtitle: number,
firstImage: number,
lastImage: number
lastImage: number,
uncertain: boolean,
}
export interface AardTestResults {
@ -20,38 +21,18 @@ export interface AardTestResults {
blackLevel: number, // is cumulative
blackThreshold: number, // is cumulative
guardLine: {
top: number, // is cumulative
bottom: number, // is cumulative
invalidated: boolean,
cornerViolated: [boolean, boolean, boolean, boolean],
cornerPixelsViolated: [0,0,0,0]
},
imageLine: {
top: number, // is cumulative
bottom: number, // is cumulative
invalidated: boolean
front: number,
back: number,
},
aspectRatioCheck: {
topRows: [number, number, number],
topQuality: [number, number, number],
bottomRows: [number, number, number],
bottomQuality: [number, number, number],
topCandidate: number,
topCandidateQuality: number,
bottomCandidate: number,
bottomCandidateDistance: number,
bottomCandidateQuality: number,
topRowsDifferenceMatrix: [number, number, number],
bottomRowsDifferenceMatrix: [number, number, number],
frontCandidate: number,
backCandidate: number,
},
aspectRatioUncertain: boolean,
topRowUncertain: boolean,
bottomRowUncertain: boolean,
aspectRatioUpdated: boolean,
activeAspectRatio: number, // is cumulative
letterboxSize: number,
letterboxOffset: number,
logoDetected: [boolean, boolean, boolean, boolean]
aspectRatioInvalid: boolean,
subtitleScan: {
top: number,
@ -63,7 +44,6 @@ export interface AardTestResults {
}
},
aspectRatioUncertainReason?: AardUncertainReason,
aspectRatioUncertainEdges: number,
aspectRatioInvalidReason?: string,
}
@ -76,34 +56,14 @@ export function initAardTestResults(settings: AardSettings): AardTestResults {
blackLevel: settings.blackLevels.defaultBlack,
blackThreshold: 16,
guardLine: {
top: -1,
bottom: -1,
invalidated: false,
cornerViolated: [false, false, false, false],
cornerPixelsViolated: [0,0,0,0]
},
imageLine: {
top: -1,
bottom: -1,
invalidated: false,
front: -1,
back: -1,
},
aspectRatioCheck: {
topRows: [-1, -1, -1],
topQuality: [0, 0, 0],
bottomRows: [-1, -1, -1],
bottomQuality: [0, 0, 0],
topCandidate: 0,
topCandidateQuality: 0,
bottomCandidate: 0,
bottomCandidateDistance: 0,
bottomCandidateQuality: 0,
topRowsDifferenceMatrix: [0, 0, 0],
bottomRowsDifferenceMatrix: [0, 0, 0],
frontCandidate: 0,
backCandidate: 0,
},
aspectRatioUncertain: false,
aspectRatioUncertainEdges: 0,
topRowUncertain: false,
bottomRowUncertain: false,
subtitleDetected: false,
subtitleScan: {
top: -1,
@ -116,7 +76,8 @@ export function initAardTestResults(settings: AardSettings): AardTestResults {
firstSubtitle: -1,
lastSubtitle: -1,
firstImage: -1,
lastImage: -1
lastImage: -1,
uncertain: false,
},
bottom: {
firstBlank: -1,
@ -124,7 +85,8 @@ export function initAardTestResults(settings: AardSettings): AardTestResults {
firstSubtitle: -1,
lastSubtitle: -1,
firstImage: -1,
lastImage: -1
lastImage: -1,
uncertain: false,
}
}
},
@ -132,45 +94,20 @@ export function initAardTestResults(settings: AardSettings): AardTestResults {
activeAspectRatio: 0,
letterboxSize: 0,
letterboxOffset: 0,
logoDetected: [false, false, false, false],
aspectRatioInvalid: false,
}
}
export function resetGuardLine(results: AardTestResults) {
results.guardLine.top = -1;
results.guardLine.bottom = -1;
results.imageLine.invalidated = false;
results.guardLine.invalidated = false;
results.guardLine.cornerViolated[0] = false;
results.guardLine.cornerViolated[1] = false;
results.guardLine.cornerViolated[2] = false;
results.guardLine.cornerViolated[3] = false;
results.guardLine.cornerPixelsViolated[0] = 0;
results.guardLine.cornerPixelsViolated[1] = 0;
results.guardLine.cornerPixelsViolated[2] = 0;
results.guardLine.cornerPixelsViolated[3] = 0;
results.guardLine.front = -1;
results.guardLine.back = -1;
}
export function resetAardTestResults(results: AardTestResults): void {
results.isFinished = false;
results.lastStage = 0;
results.imageLine.invalidated = false;
results.guardLine.invalidated = false;
results.guardLine.cornerViolated[0] = false;
results.guardLine.cornerViolated[1] = false;
results.guardLine.cornerViolated[2] = false;
results.guardLine.cornerViolated[3] = false;
results.guardLine.cornerPixelsViolated[0] = 0;
results.guardLine.cornerPixelsViolated[1] = 0;
results.guardLine.cornerPixelsViolated[2] = 0;
results.guardLine.cornerPixelsViolated[3] = 0;
// results.letterboxWidth = 0;
// results.letterboxOffset = 0;
results.aspectRatioUpdated = false;
results.aspectRatioUncertainReason = null;
results.topRowUncertain = false;
results.bottomRowUncertain = false;
results.aspectRatioInvalid = false;
results.letterboxOrientation = LetterboxOrientation.NotKnown;
}

View File

@ -2,7 +2,7 @@
"manifest_version": 3,
"name": "Ultrawidify",
"description": "Removes black bars on ultrawide videos and offers advanced options to fix aspect ratio.",
"version": "6.3.94",
"version": "6.3.97",
"icons": {
"32":"res/icons/uw-32.png",
"64":"res/icons/uw-64.png"