Tried implementing some checks that would prevent aspect ratio from changing if our edge candidate is text on black background.

This commit is contained in:
Tamius Han 2018-04-11 00:19:44 +02:00
parent 3740f2c487
commit 59d741b8a5
3 changed files with 207 additions and 58 deletions

View File

@ -62,6 +62,18 @@ var ExtensionConf = {
// continue with search. It's pointless, because black edge is higher/lower than we // 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) // are now. (NOTE: keep this less than 1 in case we implement logo detection)
edgeTolerancePx: 1, // tests for edge detection are performed this far away from detected row edgeTolerancePx: 1, // tests for edge detection are performed this far away from detected row
},
pillarTest: {
ignoreThinPillarsPx: 5, // ignore pillars that are less than this many pixels thick.
allowMisaligned: 0.05 // left and right edge can vary this much (%)
},
textLineTest: {
nonTextPulse: 0.10, // if a single continuous pulse has this many non-black pixels, we aren't dealing
// with text. This value is relative to canvas width (%)
pulsesToConfirm: 10, // this is a treshold to confirm we're seeing text.
pulsesToConfirmIfHalfBlack: 5, // this is the treshold to confirm we're seeing text if longest black pulse
// is over 50% of the canvas width
testRowOffset: 0.02 // we test this % of height from detected edge
} }
}, },
arChange: { arChange: {

View File

@ -147,14 +147,16 @@ var _pd_checkPlayerSizeChange = function(){
if(GlobalVars.playerDimensions.element == undefined) if(GlobalVars.playerDimensions.element == undefined)
return true; return true;
// if(GlobalVars.playerDimensions.fullscreen){
// return ! _pd_isFullScreen();
// }
if(GlobalVars.playerDimensions.width != GlobalVars.playerDimensions.element.offsetWidth || GlobalVars.playerDimensions.height != GlobalVars.playerDimensions.element.offsetHeight ){ if(GlobalVars.playerDimensions.width != GlobalVars.playerDimensions.element.offsetWidth || GlobalVars.playerDimensions.height != GlobalVars.playerDimensions.element.offsetHeight ){
return true; return true;
} }
// if(GlobalVars.playerDimensions.fullscreen){
// return ! _pd_isFullScreen();
// }
return false; return false;
} }

View File

@ -475,6 +475,9 @@ var _ard_vdraw_but_for_reals = function() {
// per video/pageload instead of every time letterbox goes away (this can happen more than once per vid) // per video/pageload instead of every time letterbox goes away (this can happen more than once per vid)
GlobalVars.arDetect.noLetterboxCanvasReset = false; GlobalVars.arDetect.noLetterboxCanvasReset = false;
console.log("ping!")
// let's do a quick test to see if we're on a black frame // let's do a quick test to see if we're on a black frame
// TODO: reimplement but with less bullshit // TODO: reimplement but with less bullshit
@ -524,6 +527,24 @@ var _ard_vdraw_but_for_reals = function() {
} }
// će se razmerje stranic spreminja iz ožjega na širšega, potem najprej poglejmo za prisotnostjo navpičnih črnih obrob.
// če so prisotne navpične obrobe tudi na levi in desni strani, potlej obstaja možnost, da gre za logo na črnem ozadju.
// v tem primeru obstaja nevarnost, da porežemo preveč. Ker obstaja dovolj velika možnost, da bi porezali preveč, rajši
// ne naredimo ničesar.
//
// If aspect ratio changes from narrower to wider, we first check for presence of pillarbox. Presence of pillarbox indicates
// a chance of a logo on black background. We could cut easily cut too much. Because there's a somewhat significant chance
// that we will cut too much, we rather avoid doing anything at all. There's gonna be a next chance.
if(! imageDetectResult){
if(pillarTest(image)){
console.log("pillarboxing, doing jack shit")
delete image;
triggerTimeout = _ard_getTimeout(baseTimeout, startTime);
_ard_vdraw(triggerTimeout);
return;
}
}
// pa poglejmo, kje se končajo črne letvice na vrhu in na dnu videa. // pa poglejmo, kje se končajo črne letvice na vrhu in na dnu videa.
// let's see where black bars end. // let's see where black bars end.
GlobalVars.sampleCols_current = sampleCols.length; GlobalVars.sampleCols_current = sampleCols.length;
@ -537,11 +558,31 @@ var _ard_vdraw_but_for_reals = function() {
// console.log("SAMPLES:", blackbarSamples, "candidates:", edgeCandidates, "post:", edgePost,"\n\nblack level:",GlobalVars.arDetect.blackLevel, "tresh:", GlobalVars.arDetect.blackLevel + ExtensionConf.arDetect.blackbarTreshold); // console.log("SAMPLES:", blackbarSamples, "candidates:", edgeCandidates, "post:", edgePost,"\n\nblack level:",GlobalVars.arDetect.blackLevel, "tresh:", GlobalVars.arDetect.blackLevel + ExtensionConf.arDetect.blackbarTreshold);
if(edgePost.status == "ar_known"){ if(edgePost.status == "ar_known"){
// zaznali smo rob — vendar pa moramo pred obdelavo še preveriti, ali ni "rob" slučajno besedilo. Če smo kot rob pofočkali
// besedilo, potem to ni veljaven rob. Razmerja stranic se zato ne bomo pipali.
// we detected an edge — but before we process it, we need to check if the "edge" isn't actually some text. If the detected
// edge is actually some text on black background, we shouldn't touch the aspect ratio. Whatever we detected is invalid.
var textEdge = false;;
if(edgePost.guardLineTop != null){
var row = edgePost.guardLineTop + ~~(GlobalVars.canvas.height * ExtensionConf.arDetect.textLineTest.testRowOffset);
textEdge |= textLineTest(image, row);
}
if(edgePost.guardLineTop != null){
var row = edgePost.guardLineTop - ~~(GlobalVars.canvas.height * ExtensionConf.arDetect.textLineTest.testRowOffset);
textEdge |= textLineTest(image, row);
}
if(!textEdge){
_ard_processAr(GlobalVars.video, GlobalVars.canvas.width, GlobalVars.canvas.height, edgePost.blackbarWidth, null, fallbackMode); _ard_processAr(GlobalVars.video, GlobalVars.canvas.width, GlobalVars.canvas.height, edgePost.blackbarWidth, null, fallbackMode);
// we also know edges for guardline, so set them // we also know edges for guardline, so set them
GlobalVars.arDetect.guardLine.top = edgePost.guardLineTop; GlobalVars.arDetect.guardLine.top = edgePost.guardLineTop;
GlobalVars.arDetect.guardLine.bottom = edgePost.guardLineBottom; GlobalVars.arDetect.guardLine.bottom = edgePost.guardLineBottom;
}
else{
console.log("detected text on edges, dooing nothing")
}
delete image; delete image;
triggerTimeout = _ard_getTimeout(baseTimeout, startTime); triggerTimeout = _ard_getTimeout(baseTimeout, startTime);
@ -558,66 +599,160 @@ var _ard_vdraw_but_for_reals = function() {
delete image; delete image;
} }
var getBlackRatioEstimate = function(image){ var pillarTest = function(image){
var blackbarTreshold, upper, lower; // preverimo, če na sliki obstajajo navpične črne obrobe. Vrne 'true' če so zaznane (in če so približno enako debele), 'false' sicer.
// true vrne tudi, če zaznamo preveč črnine.
// <==XX(::::}----{::::)XX==>
// checks the image for presence of vertical pillars. Less accurate than 'find blackbar limits'. If we find a non-black object that's
// roughly centered, we return true. Otherwise we return false.
// we also return true if we detect too much black
var blackbarTreshold, upper, lower;
blackbarTreshold = GlobalVars.arDetect.blackLevel + ExtensionConf.arDetect.blackbarTreshold; blackbarTreshold = GlobalVars.arDetect.blackLevel + ExtensionConf.arDetect.blackbarTreshold;
var sampleRows = 5;
var sampleCols = 10; // has 1 more than actually
var spread = 0.4; // how far from middle the samples go var middleRowStart = (GlobalVars.canvas.height >> 1) * GlobalVars.canvas.width;
var middleRowEnd = middleRowStart + GlobalVars.canvas.width - 1;
var rowOffset = ~~(GlobalVars.canvas.height / (spread >> 1)); var rowStart = middleRowStart << 2;
var rowSpacing = ~~(GlobalVars.canvas.height * spread / sampleRows); var midpoint = (middleRowStart + (GlobalVars.canvas.width >> 1)) << 2
var colSpacing = ~~(GlobalVars.canvas.width / sampleCols) >> 2; var rowEnd = middleRowEnd << 2;
var colOffset = colSpacing >> 1;
var rowStart; var edge_left = -1; edge_right = -1;
var blackCount = 0, blackRatio, totalSamples = sampleCols * (sampleCols - 1); // preverimo na levi strani
// let's check for edge on the left side
for(var i = 0; i < sampleRows; i++){ for(var i = rowStart; i < midpoint; i+=4){
rowStart = ((rowOffset * GlobalVars.canvas.width) << 2) + colOffset;
colOffset = rowStart;
for(var j = 1; j < sampleCols; j++){
if(image[colOffset] > blackbarTreshold || image[colOffset+1] > blackbarTreshold || image[colOffset+2] > blackbarTreshold){
blackCount++
}
colOffset += colSpacing;
}
rowOffset += rowSpacing;
}
rowStart = ((edge_upper * GlobalVars.canvas.width) << 2) + offset;
rowEnd = rowStart + ( GlobalVars.canvas.width << 2 ) - (offset * 2);
for(var i = rowStart; i < rowEnd; i+=4){
// we track sections that go over what's supposed to be a black line, so we can suggest more
// columns to sample
if(image[i] > blackbarTreshold || image[i+1] > blackbarTreshold || image[i+2] > blackbarTreshold){ if(image[i] > blackbarTreshold || image[i+1] > blackbarTreshold || image[i+2] > blackbarTreshold){
if(firstOffender < 0){ edge_left = (i - rowStart) >> 2;
firstOffender = (i * 0.25) - rowStart; break;
offenderCount++;
offenders.push({x: firstOffender, width: 1})
} }
else{
offenders[offenderCount].width++
}
}
else{
// is that a black pixel again? Let's reset the 'first offender'
firstOffender = -1;
} }
// preverimo na desni strani
// check on the right
for(var i = rowEnd; i > midpoint; i-= 4){
if(image[i] > blackbarTreshold || image[i+1] > blackbarTreshold || image[i+2] > blackbarTreshold){
edge_right = GlobalVars.canvas.width - ((i - rowStart) >> 2);
break;
} }
}
// če je katerikoli -1, potem imamo preveč črnine
// we probably have too much black if either of those two is -1
if(edge_left == -1 || edge_right == -1){
return true;
}
// če sta oba robova v mejah merske napake, potem vrnemo 'false'
// if both edges resemble rounding error, we retunr 'false'
if(edge_left < ExtensionConf.arDetect.pillarTest.ignoreThinPillarsPx && edge_right < ExtensionConf.arDetect.pillarTest.ignoreThinPillarsPx){
return false;
}
var edgeError = ExtensionConf.arDetect.pillarTest.allowMisaligned;
var error_low = 1 - edgeError;
var error_hi = 1 + edgeError;
// če sta 'edge_left' in 'edge_right' podobna/v mejah merske napake, potem vrnemo true — lahko da smo našli logo na sredini zaslona
// if 'edge_left' and 'edge_right' are similar enough to each other, we return true. If we found a logo in a black frame, we could
// crop too eagerly
if( (edge_left * error_low) < edge_right &&
(edge_left * error_hi) > edge_right ){
return true;
}
// če se ne zgodi nič od neštetega, potem nismo našli problemov
// if none of the above, we haven't found a problem
return false;
} }
var textLineTest = function(image, row){
// preverimo, če vrstica vsebuje besedilo na črnem ozadju. Če ob pregledu vrstice naletimo na veliko sprememb
// iz črnega v ne-črno, potem obstaja možnost, da gledamo besedilo. Prisotnost take vrstice je lahko znak, da
// zaznano razmerje stranic ni veljavno
//
// vrne 'true' če zazna text, 'false' drugače.
//
//
// check if line contains any text. If line scan reveals a lot of changes from black to non-black there's a
// chance we're looking at text on a black background. If we detect text near what we think is an edge of the
// video, there's a good chance we're about to incorrectly adjust the aspect ratio.
//
// returns 'true' if text is detected, 'false' otherwise
var blackbarTreshold = GlobalVars.arDetect.blackLevel + ExtensionConf.arDetect.blackbarTreshold;
var nontextTreshold = GlobalVars.canvas.width * ExtensionConf.arDetect.textLineTest.nonTextPulse;
var rowStart = (row * GlobalVars.canvas.width) << 2;
var rowEnd = rowStart + (GlobalVars.canvas.width << 2);
var pulse = false;
var currentPulseLength = 0, pulseCount = 0;
var pulses = [];
var longestBlack = 0;
// preglejmo vrstico
// analyse the row
for(var i = rowStart; i < rowEnd; i+= 4){
if(pulse){
if(image[i] < blackbarTreshold || image[i+1] < blackbarTreshold || image[i+2] < blackbarTreshold){
// pulses.push(currentPulseLength);
pulseCount++;
pulse = false;
currentPulseLength = 0;
}
else{
currentPulseLength++;
// če najdemo dovolj dolgo zaporedje ne-črnih točk, potem vrnemo 'false' — dobili smo legitimen rob
// if we find long enough uninterrupted line of non-black point, we fail the test. We found a legit edge.
if(currentPulseLength > nontextTreshold){
return false;
}
}
}
else{
if(image[i] > blackbarTreshold || image[i+1] > blackbarTreshold || image[i+2] > blackbarTreshold){
if(currentPulseLength > longestBlack){
longestBlack = currentPulseLength;
}
pulse = true;
currentPulseLength = 0;
}
else{
currentPulseLength++;
}
}
}
if(pulse){
pulseCount++;
// pulses.push(currentPulseLength);
}
// pregledamo rezultate:
// analyse the results
console.log("pulse test:\n\npulses:", pulseCount, "longest black:", longestBlack);
// če smo zaznali dovolj pulzov, potem vrnemo res
// if we detected enough pulses, we return true
if(pulseCount > ExtensionConf.arDetect.textLineTest.pulsesToConfirm){
return true;
}
// če je najdaljša neprekinjena črta črnih pikslov širša od polovice širine je merilo za zaznavanje
// besedila rahlo milejše
// if the longest uninterrupted line of black pixels is wider than half the width, we use a more
// forgiving standard for determining if we found text
if( longestBlack > (GlobalVars.canvas.width >> 1) &&
pulseCount > ExtensionConf.arDetect.textLineTest.pulsesToConfirmIfHalfBlack ){
return true;
}
// če pridemo do sem, potem besedilo ni bilo zaznano
// if we're here, no text was detected
return false;
}
var _ard_guardLineCheck = function(image, fallbackMode){ var _ard_guardLineCheck = function(image, fallbackMode){
// this test tests for whether we crop too aggressively // this test tests for whether we crop too aggressively
@ -998,14 +1133,14 @@ var _ard_guardLineImageDetect = function(image, fallbackMode){
// preglejmo obe vrstici - tukaj po pravilih ne bi smeli iti prek mej platna. ne rabimo preverjati // preglejmo obe vrstici - tukaj po pravilih ne bi smeli iti prek mej platna. ne rabimo preverjati
// check both rows - by the rules and definitions, we shouldn't go out of bounds here. no need to check, then // check both rows - by the rules and definitions, we shouldn't go out of bounds here. no need to check, then
// if(fallbackMode){ // if(fallbackMode){
// var edge_upper = ExtensionConf.arDetect.fallbackMode.noTriggerZonePx; // var edge_upper = ExtensionConf.arDetect.fallbackMode.noTriggerZonePx;
// var edge_lower = GlobalVars.canvas.height - ExtensionConf.arDetect.fallbackMode.noTriggerZonePx - 1; // var edge_lower = GlobalVars.canvas.height - ExtensionConf.arDetect.fallbackMode.noTriggerZonePx - 1;
// } // }
// else{ // else{
var edge_upper = edges.top + ExtensionConf.arDetect.guardLine.edgeTolerancePx; var edge_upper = edges.top + ExtensionConf.arDetect.guardLine.edgeTolerancePx;
var edge_lower = edges.bottom - ExtensionConf.arDetect.guardLine.edgeTolerancePx; var edge_lower = edges.bottom - ExtensionConf.arDetect.guardLine.edgeTolerancePx;
// } // }
// koliko pikslov rabimo zaznati, da je ta funkcija uspe. Tu dovoljujemo tudi, da so vsi piksli na enem // koliko pikslov rabimo zaznati, da je ta funkcija uspe. Tu dovoljujemo tudi, da so vsi piksli na enem
// robu (eden izmed robov je lahko v celoti črn) // robu (eden izmed robov je lahko v celoti črn)
@ -1073,7 +1208,7 @@ var _ard_edgePostprocess = function(edges, canvasHeight){
} }
} }
// console.log("count top:",edges.edgeCandidatesTopCount, "edges:", edges, "edgesTop[]", edgesTop); // console.log("count top:",edges.edgeCandidatesTopCount, "edges:", edges, "edgesTop[]", edgesTop);
// če za vsako stran (zgoraj in spodaj) poznamo vsaj enega kandidata, potem lahko preverimo nekaj // če za vsako stran (zgoraj in spodaj) poznamo vsaj enega kandidata, potem lahko preverimo nekaj
// stvari // stvari