From a3e59f0243cd08a832323610dc8ae6c5a3533e0e Mon Sep 17 00:00:00 2001 From: johan Date: Sun, 27 Oct 2013 09:25:02 +0100 Subject: [PATCH] Rewrite of black border detector to fix problems with overscan and xbmc video calibration settings Former-commit-id: ed6dd4e6872ea69d682096a82e108a3f7e7ca4ae --- libsrc/hyperion/BlackBorderDetector.cpp | 125 +++++++---------------- libsrc/hyperion/BlackBorderDetector.h | 35 ++----- libsrc/hyperion/BlackBorderProcessor.cpp | 74 ++++++++------ libsrc/hyperion/BlackBorderProcessor.h | 2 +- libsrc/hyperion/ImageProcessor.cpp | 18 ++-- test/TestBlackBorderDetector.cpp | 29 +++++- test/TestBlackBorderProcessor.cpp | 18 ++-- 7 files changed, 134 insertions(+), 167 deletions(-) diff --git a/libsrc/hyperion/BlackBorderDetector.cpp b/libsrc/hyperion/BlackBorderDetector.cpp index afc3041e..3fe34c08 100644 --- a/libsrc/hyperion/BlackBorderDetector.cpp +++ b/libsrc/hyperion/BlackBorderDetector.cpp @@ -11,100 +11,53 @@ BlackBorderDetector::BlackBorderDetector() BlackBorder BlackBorderDetector::process(const RgbImage& image) { - int firstNonBlackPixelTop = -1; - int firstNonBlackPixelLeft = -1; + // only test the topleft third of the image + int width = image.width() /3; + int height = image.height() / 3; + int maxSize = std::max(width, height); - // Find the non-black pixel at the top-half border - for (unsigned x=0; x 0; --firstNonBlackXPixelIndex) + { + const RgbColor& color = image(firstNonBlackXPixelIndex-1, firstNonBlackYPixelIndex); + if (isBlack(color)) + { + break; + } + } + + // expand image to the top + for(; firstNonBlackYPixelIndex > 0; --firstNonBlackYPixelIndex) + { + const RgbColor& color = image(firstNonBlackXPixelIndex, firstNonBlackYPixelIndex-1); + if (isBlack(color)) + { + break; + } + } + + // Construct result BlackBorder detectedBorder; - detectedBorder.type = BlackBorder::unknown; - - if (firstNonBlackPixelTop == 0 /*&& firstNonBlackPixelLeft == 0*/) - { - // No black border - // C-?-?-? ... - // ? +---- - // ? | - // ? | - // : - - detectedBorder.type = BlackBorder::none; - detectedBorder.size = -1; - } - else if (firstNonBlackPixelTop < 0) - { - if (firstNonBlackPixelLeft < 0) - { - // We don't know - // B-B-B-B ... - // B +---- ... - // B | - // B | - // : - - detectedBorder.type = BlackBorder::unknown; - detectedBorder.size = -1; - } - else //(firstNonBlackPixelLeft > 0) - { - // Border at top of screen - // B-B-B-B ... - // B +---- ... - // C | - // ? | - // : - - detectedBorder.type = BlackBorder::horizontal; - detectedBorder.size = firstNonBlackPixelLeft; - } - } - else // (firstNonBlackPixelTop > 0) - { - if (firstNonBlackPixelLeft < 0) - { - // Border at left of screen - // B-B-C-? ... - // B +---- ... - // B | - // B | - // : - - detectedBorder.type = BlackBorder::vertical; - detectedBorder.size = firstNonBlackPixelTop; - } - else //(firstNonBlackPixelLeft > 0) - { - // No black border - // B-B-C-? ... - // B +---- - // C | - // ? | - // : - - detectedBorder.type = BlackBorder::none; - detectedBorder.size = -1; - } - } - + detectedBorder.unknown = firstNonBlackXPixelIndex == -1 || firstNonBlackYPixelIndex == -1; + detectedBorder.horizontalSize = firstNonBlackYPixelIndex; + detectedBorder.verticalSize = firstNonBlackXPixelIndex; return detectedBorder; } diff --git a/libsrc/hyperion/BlackBorderDetector.h b/libsrc/hyperion/BlackBorderDetector.h index 3827ea5f..7f0a0b59 100644 --- a/libsrc/hyperion/BlackBorderDetector.h +++ b/libsrc/hyperion/BlackBorderDetector.h @@ -11,22 +11,14 @@ namespace hyperion /// struct BlackBorder { - /// - /// Enumeration of the possible types of detected borders - /// - enum Type - { - none, - horizontal, - vertical, - unknown - }; + /// Falg indicating if the border is unknown + bool unknown; - /// The type of detected border - Type type; + /// The size of the detected horizontal border + int horizontalSize; - /// The size of detected border (negative if not applicable) - int size; + /// The size of the detected vertical border + int verticalSize; /// /// Compares this BlackBorder to the given other BlackBorder @@ -37,24 +29,19 @@ namespace hyperion /// inline bool operator== (const BlackBorder& other) const { - switch (type) + if (unknown) { - case none: - case unknown: - return other.type == type; - case horizontal: - case vertical: - return type == other.type && size == other.size; + return other.unknown; } - return false; + return other.unknown==false && horizontalSize==other.horizontalSize && verticalSize==other.verticalSize; } }; /// /// The BlackBorderDetector performs detection of black-borders on a single image. - /// The detector will scan the border of the upper-left quadrant of an image. Based on detected - /// black pixels it will give an estimate of the black-border. + /// The detector will search for the upper left corner of the picture in the frame. + /// Based on detected black pixels it will give an estimate of the black-border. /// class BlackBorderDetector { diff --git a/libsrc/hyperion/BlackBorderProcessor.cpp b/libsrc/hyperion/BlackBorderProcessor.cpp index 46896978..6d355cb7 100644 --- a/libsrc/hyperion/BlackBorderProcessor.cpp +++ b/libsrc/hyperion/BlackBorderProcessor.cpp @@ -12,26 +12,33 @@ BlackBorderProcessor::BlackBorderProcessor( _borderSwitchCnt(borderFrameCnt), _blurRemoveCnt(blurRemoveCnt), _detector(), - _currentBorder({BlackBorder::unknown, 0}), - _previousDetectedBorder({BlackBorder::unknown, 0}), + _currentBorder({true, -1, -1}), + _previousDetectedBorder({true, -1, -1}), _consistentCnt(0) { } BlackBorder BlackBorderProcessor::getCurrentBorder() const { - if (_currentBorder.size > 0) - { - return {_currentBorder.type, _currentBorder.size+int(_blurRemoveCnt)}; - } - return _currentBorder; } bool BlackBorderProcessor::process(const RgbImage& image) { - const BlackBorder imageBorder = _detector.process(image); + // get the border for the single image + BlackBorder imageBorder = _detector.process(image); + // add blur to the border + if (imageBorder.horizontalSize > 0) + { + imageBorder.horizontalSize += _blurRemoveCnt; + } + if (imageBorder.verticalSize > 0) + { + imageBorder.verticalSize += _blurRemoveCnt; + } + + // set the consistency counter if (imageBorder == _previousDetectedBorder) { ++_consistentCnt; @@ -42,6 +49,7 @@ bool BlackBorderProcessor::process(const RgbImage& image) _consistentCnt = 0; } + // check if there is a change if (_currentBorder == imageBorder) { // No change required @@ -49,36 +57,38 @@ bool BlackBorderProcessor::process(const RgbImage& image) } bool borderChanged = false; - switch (imageBorder.type) + if (imageBorder.unknown) { - case BlackBorder::none: - if (_consistentCnt == 0) - { - _currentBorder = imageBorder; - borderChanged = true; - } - break; - case BlackBorder::horizontal: - if (_currentBorder.type == BlackBorder::vertical || imageBorder.size < _currentBorder.size || _consistentCnt == _borderSwitchCnt) - { - _currentBorder = imageBorder; - borderChanged = true; - } - break; - case BlackBorder::vertical: - if (_currentBorder.type == BlackBorder::horizontal || imageBorder.size < _currentBorder.size || _consistentCnt == _borderSwitchCnt) - { - _currentBorder = imageBorder; - borderChanged = true; - } - break; - case BlackBorder::unknown: + // apply the unknown border if we consistently can't determine a border if (_consistentCnt == _unknownSwitchCnt) { _currentBorder = imageBorder; borderChanged = true; } - break; + } + else + { + // apply the detected border if it has been detected consistently + if (_currentBorder.unknown || _consistentCnt == _borderSwitchCnt) + { + _currentBorder = imageBorder; + borderChanged = true; + } + else + { + // apply smaller borders immediately + if (imageBorder.verticalSize < _currentBorder.verticalSize) + { + _currentBorder.verticalSize = imageBorder.verticalSize; + borderChanged = true; + } + + if (imageBorder.horizontalSize < _currentBorder.horizontalSize) + { + _currentBorder.horizontalSize = imageBorder.horizontalSize; + borderChanged = true; + } + } } return borderChanged; diff --git a/libsrc/hyperion/BlackBorderProcessor.h b/libsrc/hyperion/BlackBorderProcessor.h index 89c59198..d785f696 100644 --- a/libsrc/hyperion/BlackBorderProcessor.h +++ b/libsrc/hyperion/BlackBorderProcessor.h @@ -20,7 +20,7 @@ namespace hyperion /// @param borderFrameCnt The number of frames(images) that need to contain a vertical or /// horizontal border becomes the current border /// @param blurRemoveCnt The size to add to a horizontal or vertical border (because the - /// outer pixels is blurred (black and color combined)) + /// outer pixels is blurred (black and color combined due to image scaling)) /// BlackBorderProcessor( const unsigned unknownFrameCnt, diff --git a/libsrc/hyperion/ImageProcessor.cpp b/libsrc/hyperion/ImageProcessor.cpp index 3b91bf9e..c851c7b3 100644 --- a/libsrc/hyperion/ImageProcessor.cpp +++ b/libsrc/hyperion/ImageProcessor.cpp @@ -78,24 +78,18 @@ void ImageProcessor::verifyBorder(const RgbImage& image) // Clean up the old mapping delete mImageToLeds; - switch (border.type) + if (border.unknown) { - case BlackBorder::none: - case BlackBorder::unknown: // Construct a new buffer and mapping mImageToLeds = new ImageToLedsMap(image.width(), image.height(), 0, 0, mLedString.leds()); - break; - case BlackBorder::horizontal: + } + else + { // Construct a new buffer and mapping - mImageToLeds = new ImageToLedsMap(image.width(), image.height(), border.size, 0, mLedString.leds()); - break; - case BlackBorder::vertical: - // Construct a new buffer and mapping - mImageToLeds = new ImageToLedsMap(image.width(), image.height(), 0, border.size, mLedString.leds()); - break; + mImageToLeds = new ImageToLedsMap(image.width(), image.height(), border.horizontalSize, border.verticalSize, mLedString.leds()); } - std::cout << "CURRENT BORDER TYPE: " << _borderProcessor->getCurrentBorder().type << " (size=" << _borderProcessor->getCurrentBorder().size << ")" << std::endl; + std::cout << "CURRENT BORDER TYPE: unknown=" << border.unknown << " hor.size=" << border.horizontalSize << " vert.size=" << border.verticalSize << std::endl; } } diff --git a/test/TestBlackBorderDetector.cpp b/test/TestBlackBorderDetector.cpp index ba14b377..63954fc5 100644 --- a/test/TestBlackBorderDetector.cpp +++ b/test/TestBlackBorderDetector.cpp @@ -45,7 +45,7 @@ int TC_NO_BORDER() { RgbImage image = createImage(64, 64, 0, 0); BlackBorder border = detector.process(image); - if (border.type != BlackBorder::none) + if (border.unknown != false && border.horizontalSize != 0 && border.verticalSize != 0) { std::cerr << "Failed to correctly detect no border" << std::endl; result = -1; @@ -64,7 +64,7 @@ int TC_TOP_BORDER() { RgbImage image = createImage(64, 64, 12, 0); BlackBorder border = detector.process(image); - if (border.type != BlackBorder::horizontal || border.size != 12) + if (border.unknown != false && border.horizontalSize != 12 && border.verticalSize != 0) { std::cerr << "Failed to correctly detect horizontal border with correct size" << std::endl; result = -1; @@ -83,7 +83,7 @@ int TC_LEFT_BORDER() { RgbImage image = createImage(64, 64, 0, 12); BlackBorder border = detector.process(image); - if (border.type != BlackBorder::vertical || border.size != 12) + if (border.unknown != false && border.horizontalSize != 0 && border.verticalSize != 12) { std::cerr << "Failed to detected vertical border with correct size" << std::endl; result = -1; @@ -93,6 +93,24 @@ int TC_LEFT_BORDER() return result; } +int TC_DUAL_BORDER() +{ + int result = 0; + + BlackBorderDetector detector; + + { + RgbImage image = createImage(64, 64, 12, 12); + BlackBorder border = detector.process(image); + if (border.unknown != false && border.horizontalSize != 12 && border.verticalSize != 12) + { + std::cerr << "Failed to detected two-sided border" << std::endl; + result = -1; + } + } + return result; +} + int TC_UNKNOWN_BORDER() { int result = 0; @@ -100,9 +118,9 @@ int TC_UNKNOWN_BORDER() BlackBorderDetector detector; { - RgbImage image = createImage(64, 64, 12, 12); + RgbImage image = createImage(64, 64, 30, 30); BlackBorder border = detector.process(image); - if (border.type != BlackBorder::unknown) + if (border.unknown != true) { std::cerr << "Failed to detected unknown border" << std::endl; result = -1; @@ -116,6 +134,7 @@ int main() TC_NO_BORDER(); TC_TOP_BORDER(); TC_LEFT_BORDER(); + TC_DUAL_BORDER(); TC_UNKNOWN_BORDER(); return 0; diff --git a/test/TestBlackBorderProcessor.cpp b/test/TestBlackBorderProcessor.cpp index 58da95fb..b8cda172 100644 --- a/test/TestBlackBorderProcessor.cpp +++ b/test/TestBlackBorderProcessor.cpp @@ -70,10 +70,11 @@ int main() } } } + // Verify that the border is indeed - if (processor.getCurrentBorder().type != BlackBorder::none) + if (processor.getCurrentBorder().unknown != false || processor.getCurrentBorder().horizontalSize != 0 || processor.getCurrentBorder().verticalSize != 0) { - std::cerr << "Incorrectlty identified 'no border' (" << processor.getCurrentBorder().type << " != " << BlackBorder::none << ")" << std::endl; + std::cerr << "Incorrectlty identified 'no border'" << std::endl; exit(EXIT_FAILURE); } @@ -99,14 +100,16 @@ int main() } } } - if (processor.getCurrentBorder().type != BlackBorder::horizontal || processor.getCurrentBorder().size != borderSize) + + if (processor.getCurrentBorder().unknown != false || processor.getCurrentBorder().horizontalSize != borderSize || processor.getCurrentBorder().verticalSize != 0) { - std::cerr << "Incorrectlty found 'horizontal border' (" << processor.getCurrentBorder().type << " != " << BlackBorder::horizontal << ")" << std::endl; + + std::cerr << "Incorrectlty found 'horizontal border' (" << processor.getCurrentBorder().unknown << "," << processor.getCurrentBorder().horizontalSize << "," << processor.getCurrentBorder().verticalSize << ")" << std::endl; exit(EXIT_FAILURE); } // Switch back (in one shot) to no border - if (!processor.process(noBorderImage) || (processor.getCurrentBorder().type != BlackBorder::none)) + if (!processor.process(noBorderImage) || (processor.getCurrentBorder().unknown != false || processor.getCurrentBorder().horizontalSize != 0 || processor.getCurrentBorder().verticalSize != 0)) { std::cerr << "Failed to switch back to 'no border' with one image" << std::endl; exit(EXIT_FAILURE); @@ -133,9 +136,10 @@ int main() } } } - if (processor.getCurrentBorder().type != BlackBorder::vertical || processor.getCurrentBorder().size != borderSize) + + if (processor.getCurrentBorder().unknown != false || processor.getCurrentBorder().horizontalSize != 0 || processor.getCurrentBorder().verticalSize != borderSize) { - std::cerr << "Incorrectlty found 'vertical border' (" << processor.getCurrentBorder().type << " != " << BlackBorder::horizontal << ")" << std::endl; + std::cerr << "Incorrectlty found 'vertical border'" << std::endl; exit(EXIT_FAILURE); }