Finish guardline/image line tests
This commit is contained in:
parent
c15d7ab28e
commit
e2dac10501
@ -10,8 +10,20 @@ import { AardStatus, initAardStatus } from './interfaces/aard-status.interface';
|
|||||||
import { AardTestResults, initAardTestResults } from './interfaces/aard-test-results.interface';
|
import { AardTestResults, initAardTestResults } from './interfaces/aard-test-results.interface';
|
||||||
import { AardTimers, initAardTimers } from './interfaces/aard-timers.interface';
|
import { AardTimers, initAardTimers } from './interfaces/aard-timers.interface';
|
||||||
|
|
||||||
// Automatic Aspect Ratio Detector
|
|
||||||
// Here's how it works:
|
/**
|
||||||
|
* /\
|
||||||
|
* //\\ Automatic
|
||||||
|
* // \\ Aspect
|
||||||
|
* // \\ Ratio
|
||||||
|
* \\ Detector
|
||||||
|
* //XXXX \\
|
||||||
|
* // \\ (Totes not a Witcher reference)
|
||||||
|
* // \\ (Witcher 2 best Witcher)
|
||||||
|
* //XXXXXXXXXXXXXX\\
|
||||||
|
*
|
||||||
|
* How it works:
|
||||||
|
*/
|
||||||
/**
|
/**
|
||||||
* [ ] Draw frame to canvas
|
* [ ] Draw frame to canvas
|
||||||
* |
|
* |
|
||||||
@ -256,6 +268,8 @@ class Aard {
|
|||||||
|
|
||||||
// we can tick manually, for debugging
|
// we can tick manually, for debugging
|
||||||
this.logger.log('info', 'init', `[ArDetector::ctor] creating new ArDetector. arid: ${this.arid}`);
|
this.logger.log('info', 'init', `[ArDetector::ctor] creating new ArDetector. arid: ${this.arid}`);
|
||||||
|
|
||||||
|
this.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
private initEventBus() {
|
private initEventBus() {
|
||||||
@ -313,6 +327,8 @@ class Aard {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// STEP 1:
|
||||||
|
// Test if corners are black. If they're not, we can immediately quit the loop.
|
||||||
this.getBlackLevelFast(
|
this.getBlackLevelFast(
|
||||||
imageData, 3, 1,
|
imageData, 3, 1,
|
||||||
this.settings.active.arDetect.canvasDimensions.sampleCanvas.width,
|
this.settings.active.arDetect.canvasDimensions.sampleCanvas.width,
|
||||||
@ -324,11 +340,28 @@ class Aard {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// STEP 2:
|
||||||
|
// Check if previously detected aspect ratio is still gucci. If it is, then
|
||||||
|
// we can quit the loop without applying any aspect ratios (unless subtitle
|
||||||
|
// detection is enabled, in which case we still run the subtitle test)
|
||||||
this.checkLetterboxShrink(
|
this.checkLetterboxShrink(
|
||||||
imageData,
|
imageData,
|
||||||
this.settings.active.arDetect.canvasDimensions.sampleCanvas.width,
|
this.settings.active.arDetect.canvasDimensions.sampleCanvas.width,
|
||||||
this.settings.active.arDetect.canvasDimensions.sampleCanvas.height
|
this.settings.active.arDetect.canvasDimensions.sampleCanvas.height
|
||||||
);
|
);
|
||||||
|
if (! this.testResults.guardLine.invalidated) {
|
||||||
|
this.checkLetterboxGrow(
|
||||||
|
imageData,
|
||||||
|
this.settings.active.arDetect.canvasDimensions.sampleCanvas.width,
|
||||||
|
this.settings.active.arDetect.canvasDimensions.sampleCanvas.height
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (! this.testResults.imageLine.invalidated) {
|
||||||
|
// TODO: ensure no aspect ratio changes happen
|
||||||
|
this.testResults.lastStage = 2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
} while (false);
|
} while (false);
|
||||||
@ -504,7 +537,11 @@ class Aard {
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if letterbox has shrunk.
|
* Checks if letterbox has shrunk. If letterbox has shrunk (image portion of the frame grows), we invalidate
|
||||||
|
* guard line data. Note that this function only sets testResults.guardline.invalidated=true, but does not
|
||||||
|
* override current guardline values.
|
||||||
|
* NOTE: if guardLine is invalidated, the function will also helpfully invalidate imageLine results. This
|
||||||
|
* will happen because invalid blackLine logically implies invalid imageLine.
|
||||||
* @param imageData
|
* @param imageData
|
||||||
* @param width
|
* @param width
|
||||||
* @param height
|
* @param height
|
||||||
@ -555,6 +592,7 @@ class Aard {
|
|||||||
}
|
}
|
||||||
if (imageData[i] > this.testResults.blackThreshold) {
|
if (imageData[i] > this.testResults.blackThreshold) {
|
||||||
this.testResults.guardLine.invalidated = true;
|
this.testResults.guardLine.invalidated = true;
|
||||||
|
this.testResults.imageLine.invalidated = true;
|
||||||
return; // no need to check further,
|
return; // no need to check further,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -601,6 +639,7 @@ class Aard {
|
|||||||
}
|
}
|
||||||
if (imageData[i] > this.testResults.blackThreshold) {
|
if (imageData[i] > this.testResults.blackThreshold) {
|
||||||
this.testResults.guardLine.invalidated = true;
|
this.testResults.guardLine.invalidated = true;
|
||||||
|
this.testResults.imageLine.invalidated = true;
|
||||||
return; // no need to check further,
|
return; // no need to check further,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -640,13 +679,18 @@ class Aard {
|
|||||||
|
|
||||||
if (dirtyCount > maxInvalidCorners) {
|
if (dirtyCount > maxInvalidCorners) {
|
||||||
this.testResults.guardLine.invalidated = true;
|
this.testResults.guardLine.invalidated = true;
|
||||||
|
this.testResults.imageLine.invalidated = true;
|
||||||
} else {
|
} else {
|
||||||
this.testResults.guardLine.invalidated = false;
|
this.testResults.guardLine.invalidated = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if letterbox has grown
|
* Checks if letterbox has grown. This test is super-efficient on frames that aren't dark,
|
||||||
|
* but is also rather inefficient if the frame is overly dark. Note that this function merely
|
||||||
|
* sets testResults.imageLine.invalidated to `true`. Correcting actual values is done during
|
||||||
|
* aspect ratio detection.
|
||||||
|
* TODO: maybe consider checking fewer pixels per line
|
||||||
* @param imageData
|
* @param imageData
|
||||||
* @param width
|
* @param width
|
||||||
* @param height
|
* @param height
|
||||||
@ -661,6 +705,198 @@ class Aard {
|
|||||||
this.testResults.imageLine.invalidated = true;
|
this.testResults.imageLine.invalidated = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let edgePosition = 0.25; // TODO: unhardcode and put into settings. Is % of total width.
|
||||||
|
const segmentPixels = width * edgePosition;
|
||||||
|
const edgeSegmentSize = segmentPixels * 4;
|
||||||
|
|
||||||
|
const detectionThreshold = width * 0.1; // TODO: unhardcoide and put into settings. Is % of total width.
|
||||||
|
let imagePixel = false;
|
||||||
|
let pixelCount = 0;
|
||||||
|
|
||||||
|
// check the top
|
||||||
|
{
|
||||||
|
const rowStart = this.testResults.imageLine.top * width * 4;
|
||||||
|
const firstSegment = rowStart + edgeSegmentSize;
|
||||||
|
const rowEnd = rowStart + (width * 4) - 4;
|
||||||
|
const secondSegment = rowEnd - edgeSegmentSize;
|
||||||
|
|
||||||
|
let i = rowStart;
|
||||||
|
|
||||||
|
// we don't run image detection in corners that may contain logos, as such corners
|
||||||
|
// may not be representative
|
||||||
|
if (! this.testResults.guardLine.cornerViolations[Corner.TopLeft]) {
|
||||||
|
while (i < firstSegment) {
|
||||||
|
imagePixel = false;
|
||||||
|
imagePixel ||= imageData[i++] > this.testResults.blackThreshold;
|
||||||
|
imagePixel ||= imageData[i++] > this.testResults.blackThreshold;
|
||||||
|
imagePixel ||= imageData[i++] > this.testResults.blackThreshold;
|
||||||
|
|
||||||
|
if (imagePixel && ++pixelCount > detectionThreshold) {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
i++; // skip over alpha channel
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (i < secondSegment) {
|
||||||
|
imagePixel = false;
|
||||||
|
imagePixel ||= imageData[i++] > this.testResults.blackThreshold;
|
||||||
|
imagePixel ||= imageData[i++] > this.testResults.blackThreshold;
|
||||||
|
imagePixel ||= imageData[i++] > this.testResults.blackThreshold;
|
||||||
|
|
||||||
|
if (imagePixel && ++pixelCount > detectionThreshold) {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
i++; // skip over alpha channel
|
||||||
|
}
|
||||||
|
if (! this.testResults.guardLine.cornerViolations[Corner.TopRight]) {
|
||||||
|
while (i < rowEnd) {
|
||||||
|
imagePixel = false;
|
||||||
|
imagePixel ||= imageData[i++] > this.testResults.blackThreshold;
|
||||||
|
imagePixel ||= imageData[i++] > this.testResults.blackThreshold;
|
||||||
|
imagePixel ||= imageData[i++] > this.testResults.blackThreshold;
|
||||||
|
|
||||||
|
if (imagePixel && ++pixelCount > detectionThreshold) {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
i++; // skip over alpha channel
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// we don't run image detection in corners that may contain logos, as such corners
|
||||||
|
// may not be representative
|
||||||
|
if (! this.testResults.guardLine.cornerViolations[Corner.TopLeft]) {
|
||||||
|
while (i < firstSegment) {
|
||||||
|
imagePixel = false;
|
||||||
|
imagePixel ||= imageData[i++] > this.testResults.blackThreshold;
|
||||||
|
imagePixel ||= imageData[i++] > this.testResults.blackThreshold;
|
||||||
|
imagePixel ||= imageData[i++] > this.testResults.blackThreshold;
|
||||||
|
|
||||||
|
if (imagePixel && ++pixelCount > detectionThreshold) {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
i++; // skip over alpha channel
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (i < secondSegment) {
|
||||||
|
imagePixel = false;
|
||||||
|
imagePixel ||= imageData[i++] > this.testResults.blackThreshold;
|
||||||
|
imagePixel ||= imageData[i++] > this.testResults.blackThreshold;
|
||||||
|
imagePixel ||= imageData[i++] > this.testResults.blackThreshold;
|
||||||
|
|
||||||
|
if (imagePixel && ++pixelCount > detectionThreshold) {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
i++; // skip over alpha channel
|
||||||
|
}
|
||||||
|
if (! this.testResults.guardLine.cornerViolations[Corner.TopRight]) {
|
||||||
|
while (i < rowEnd) {
|
||||||
|
imagePixel = false;
|
||||||
|
imagePixel ||= imageData[i++] > this.testResults.blackThreshold;
|
||||||
|
imagePixel ||= imageData[i++] > this.testResults.blackThreshold;
|
||||||
|
imagePixel ||= imageData[i++] > this.testResults.blackThreshold;
|
||||||
|
|
||||||
|
if (imagePixel && ++pixelCount > detectionThreshold) {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
i++; // skip over alpha channel
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// check the bottom
|
||||||
|
{
|
||||||
|
const rowStart = this.testResults.imageLine.bottom * width * 4;
|
||||||
|
const firstSegment = rowStart + edgeSegmentSize;
|
||||||
|
const rowEnd = rowStart + (width * 4) - 4;
|
||||||
|
const secondSegment = rowEnd - edgeSegmentSize;
|
||||||
|
|
||||||
|
let i = rowStart;
|
||||||
|
|
||||||
|
// we don't run image detection in corners that may contain logos, as such corners
|
||||||
|
// may not be representative
|
||||||
|
if (! this.testResults.guardLine.cornerViolations[Corner.TopLeft]) {
|
||||||
|
while (i < firstSegment) {
|
||||||
|
imagePixel = false;
|
||||||
|
imagePixel ||= imageData[i++] > this.testResults.blackThreshold;
|
||||||
|
imagePixel ||= imageData[i++] > this.testResults.blackThreshold;
|
||||||
|
imagePixel ||= imageData[i++] > this.testResults.blackThreshold;
|
||||||
|
|
||||||
|
if (imagePixel && ++pixelCount > detectionThreshold) {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
i++; // skip over alpha channel
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (i < secondSegment) {
|
||||||
|
imagePixel = false;
|
||||||
|
imagePixel ||= imageData[i++] > this.testResults.blackThreshold;
|
||||||
|
imagePixel ||= imageData[i++] > this.testResults.blackThreshold;
|
||||||
|
imagePixel ||= imageData[i++] > this.testResults.blackThreshold;
|
||||||
|
|
||||||
|
if (imagePixel && ++pixelCount > detectionThreshold) {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
i++; // skip over alpha channel
|
||||||
|
}
|
||||||
|
if (! this.testResults.guardLine.cornerViolations[Corner.TopRight]) {
|
||||||
|
while (i < rowEnd) {
|
||||||
|
imagePixel = false;
|
||||||
|
imagePixel ||= imageData[i++] > this.testResults.blackThreshold;
|
||||||
|
imagePixel ||= imageData[i++] > this.testResults.blackThreshold;
|
||||||
|
imagePixel ||= imageData[i++] > this.testResults.blackThreshold;
|
||||||
|
|
||||||
|
if (imagePixel && ++pixelCount > detectionThreshold) {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
i++; // skip over alpha channel
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// we don't run image detection in corners that may contain logos, as such corners
|
||||||
|
// may not be representative
|
||||||
|
if (! this.testResults.guardLine.cornerViolations[Corner.TopLeft]) {
|
||||||
|
while (i < firstSegment) {
|
||||||
|
imagePixel = false;
|
||||||
|
imagePixel ||= imageData[i++] > this.testResults.blackThreshold;
|
||||||
|
imagePixel ||= imageData[i++] > this.testResults.blackThreshold;
|
||||||
|
imagePixel ||= imageData[i++] > this.testResults.blackThreshold;
|
||||||
|
|
||||||
|
if (imagePixel && ++pixelCount > detectionThreshold) {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
i++; // skip over alpha channel
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (i < secondSegment) {
|
||||||
|
imagePixel = false;
|
||||||
|
imagePixel ||= imageData[i++] > this.testResults.blackThreshold;
|
||||||
|
imagePixel ||= imageData[i++] > this.testResults.blackThreshold;
|
||||||
|
imagePixel ||= imageData[i++] > this.testResults.blackThreshold;
|
||||||
|
|
||||||
|
if (imagePixel && ++pixelCount > detectionThreshold) {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
i++; // skip over alpha channel
|
||||||
|
}
|
||||||
|
if (! this.testResults.guardLine.cornerViolations[Corner.TopRight]) {
|
||||||
|
while (i < rowEnd) {
|
||||||
|
imagePixel = false;
|
||||||
|
imagePixel ||= imageData[i++] > this.testResults.blackThreshold;
|
||||||
|
imagePixel ||= imageData[i++] > this.testResults.blackThreshold;
|
||||||
|
imagePixel ||= imageData[i++] > this.testResults.blackThreshold;
|
||||||
|
|
||||||
|
if (imagePixel && ++pixelCount > detectionThreshold) {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
i++; // skip over alpha channel
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we came this far, we didn't get enough non-black pixels in order
|
||||||
|
// to detect image. imageLine needs to be invalidated.
|
||||||
|
this.testResults.imageLine.invalidated = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user