Improvements to gradient detection

This commit is contained in:
Tamius Han 2019-05-04 21:33:48 +02:00
parent 9a3ba39076
commit 5fbdb3822c
4 changed files with 124 additions and 14 deletions

View File

@ -3,7 +3,7 @@
const _prod = false;
var Debug = {
performanceMetrics: true, // should not be affected by debug.debug in order to allow benchmarking of the impact logging in console has
// performanceMetrics: true, // should not be affected by debug.debug in order to allow benchmarking of the impact logging in console has
init: true,
debug: true,
// debug: false,
@ -16,7 +16,7 @@ var Debug = {
// comms: true,
// showArDetectCanvas: true,
// flushStoredSettings: true,
flushStoredSettings: false,
// flushStoredSettings: false,
// playerDetectDebug: true,
// periodic: true,
// videoRescan: true,

View File

@ -45,12 +45,12 @@ var ExtensionConf = {
// samplingInterval: 10, // we sample at columns at (width/this) * [ 1 .. this - 1]
blackframe: {
sufficientColorVariance: 0.05, // calculate difference between average intensity and pixel, for every pixel for every color
sufficientColorVariance: 0.09, // calculate difference between average intensity and pixel, for every pixel for every color
// component. Average intensity is normalized to where 0 is black and 1 is biggest value for
// that component. If sum of differences between normalized average intensity and normalized
// component varies more than this % between color components, we can afford to use less strict
// cummulative treshold.
cumulativeTresholdLax: 1600,
cumulativeThresholdLax: 1600,
cumulativeThresholdStrict: 2560,// if we add values of all pixels together and get more than this, the frame is bright enough.
// (note: blackframe is 16x9 px -> 144px total. cumulative threshold can be reached fast)
blackPixelsCondition: 0.6, // How much pixels must be black (1 all, 0 none) before we consider frame as black. Takes
@ -63,6 +63,7 @@ var ExtensionConf = {
threshold: 16, // if pixel is darker than the sum of black level and this value, we count it as black
// on 0-255. Needs to be fairly high (8 might not cut it) due to compression
// artifacts in the video itself
frameThreshold: 4, // treshold, but when doing blackframe test
imageThreshold: 16, // in order to detect pixel as "not black", the pixel must be brighter than
// the sum of black level, threshold and this value.
gradientThreshold: 2, // When trying to determine thickness of the black bars, we take 2 values: position of

View File

@ -587,6 +587,8 @@ class ArDetector {
console.log("%c[ArDetect::frameCheck] Black frame analysis suggests this frame is black or too dark. Doing nothing,", "color: #fa3", bfanalysis);
}
return;
} else {
console.log("%c[ArDetect::frameCheck] Black frame analysis suggests this frame is not completely black. Doing further analysis,", "color: #3fa", bfanalysis);
}
@ -766,7 +768,7 @@ class ArDetector {
}
blackframeTest() {
if (! this.blackLevel) {
if (this.blackLevel === undefined) {
if (Debug.debug && Debug.debugArDetect) {
console.log("[ArDetect::frameCheck] black level undefined, resetting");
}
@ -786,6 +788,7 @@ class ArDetector {
let cumulativeValue = 0;
let blackPixelCount = 0;
const bfImageData = this.blackframeContext.getImageData(0, 0, cols, rows).data;
const blackTreshold = this.blackLevel + this.settings.active.arDetect.blackbar.frameTreshold;
// we do some recon for letterbox and pillarbox. While this can't determine whether letterbox/pillarbox exists
@ -800,8 +803,10 @@ class ArDetector {
pixelMax = Math.max(bfImageData[i], bfImageData[i+1], bfImageData[i+2]);
bfImageData[i+3] = pixelMax;
if (pixelMax < this.blackLevel) {
this.blackLevel = pixelMax;
if (pixelMax < blackTreshold) {
if (pixelMax < this.blackLevel) {
this.blackLevel = pixelMax;
}
blackPixelCount++;
} else {
cumulativeValue += pixelMax;
@ -865,6 +870,7 @@ class ArDetector {
blackPixelRatio: (blackPixelCount/(cols * rows)),
cumulativeValue: cumulativeValue,
hasSufficientVariance: hasSufficientVariance,
blackLevel: this.blackLevel,
variances: {
raw: {
r: var_r, g: var_g, b: var_b

View File

@ -32,6 +32,9 @@ class EdgeDetect{
if (direction == EdgeDetectPrimaryDirection.VERTICAL) {
fastCandidates = this.findCandidates(image, sampleCols, guardLineOut);
if (! this.isValidSample(fastCandidates)) {
return {status: EdgeStatus.AR_UNKNOWN};
}
// if(quality == EdgeDetectQuality.FAST){
// edges = fastCandidates; // todo: processing
// } else {
@ -140,6 +143,88 @@ class EdgeDetect{
// dont call the following outside of this class
isValidSample(samples) {
// NOTE: this is very simple and will need to be reworked in case we ever
// go for quorum-based edge detection. (Probably not gonna happen)
const topPoint = {
row: this.conf.canvas.height,
gradient: false, // does current row have a gradient sample
noGradient: false, // does current row have 100% confirmed edge sample
}
const bottomPoint = {
row: 0,
gradient: false,
noGradient: false,
}
// process the top row
for (let i = 0; i < samples.res_top.length; i++) {
// if we find new highest point, we reset gradient and noGradient
if (samples.res_top[i].black < topPoint.row) {
topPoint.row = samples.res_top[i].black;
topPoint.gradient = false;
topPoint.noGradient = false;
}
// if we're in the top row, we update gradient/no gradient
// we track gradient and nogradient points separately
if (samples.res_top[i].black === topPoint.row) {
if (samples.res_top[i].hasGradient) {
topPoint.gradient = true;
} else {
topPoint.noGradient = true;
}
}
}
// process the bottom row
for (let i = 0; i < samples.res_top.length; i++) {
// if we find new highest point, we reset gradient and noGradient
if (samples.res_top[i].black > bottomPoint.row) {
bottomPoint.row = samples.res_top[i].black;
bottomPoint.gradient = false;
bottomPoint.noGradient = false;
}
// if we're in the top row, we update gradient/no gradient
// we track gradient and nogradient points separately
if (samples.res_top[i].black === bottomPoint.row) {
if (samples.res_top[i].hasGradient) {
bottomPoint.gradient = true;
} else {
bottomPoint.noGradient = true;
}
}
}
if (topPoint.noGradient && bottomPoint.noGradient) {
return true;
}
if (! topPoint.noGradient) {
if (! bottomPoint.noGradient) {
// top sample in both is a gradient with no solid sample present in that row
// this means validation failed:
return false;
} else {
// if top gradient-only sample is closer to the edge than the bottom sample,
// validation also fails. Otherwise, we can assume success.
return (topPoint.row >= this.conf.canvas.height - bottomPoint.row);
}
}
// this is the only combination that we have to handle at this point. Because we're
// here, we know that the top row is reasonably gradient-free. We only need to check
// whether gradient-only result of bottom row is closer to the edge than than the top
// sample.
if (! bottomPoint.noGradient) {
return (topPoint.row < this.conf.canvas.height - bottomPoint.row);
}
return false;
}
edgeDetect(image, samples){
var edgeCandidatesTop = {count: 0};
var edgeCandidatesBottom = {count: 0};
@ -245,13 +330,6 @@ class EdgeDetect{
} catch (e) {
console.log("\n\nuwu fucky wucky:", e, "\n\n")
}
console.log("----------- returning: ", {
edgeCandidatesTop: edgeCandidatesTop,
edgeCandidatesTopCount: edgeCandidatesTop.count,
edgeCandidatesBottom: edgeCandidatesBottom,
edgeCandidatesBottomCount: edgeCandidatesBottom.count
});
return {
edgeCandidatesTop: edgeCandidatesTop,
@ -556,6 +634,7 @@ class EdgeDetect{
blackFound: false,
imageFound: false, // misleading name — also true if we ran over gradientSampleSize pixels from image
// whether that actually count as an image depends on how aggressive gradientDetection is
hasGradient: false,
blackRow: -1,
imageRow: -1,
lastValue: -1,
@ -709,8 +788,25 @@ class EdgeDetect{
black: c.blackRow
});
continue;
} else {
// this means we're on a gradient. We still push an object to colsOut — this is
// important. While "bad" detection doesn't help us with determining the aspect
// ratio, bad detections can prevent us from setting aspect ratio incorrectly.
// for example, if we detect a gradient closer to the frame edge than a proper
// edge, we still know that cropping based on the confirmed edges would crop too
// much of the frame. In situations like this, we must ignore the results — and
// since results are handled outside of this function, we need to pass an
// additional parameter that allows us to distinguish real results from noise.
colsOut.push({
col: c.col,
black: c.blackRow,
hasGradient: true,
});
continue;
}
} else {
// in this case, we aren't looking at a gradient. We also aren't looking at a
// valid column
continue;
}
}
@ -724,6 +820,13 @@ class EdgeDetect{
black: c.blackRow
});
continue;
} else {
colsOut.push({
col: c.col,
black: c.blackRow,
hasGradient: true,
});
continue;
}
}
}