mirror of
				https://github.com/hyperion-project/hyperion.ng.git
				synced 2025-03-01 10:33:28 +00:00 
			
		
		
		
	Added wrapper for the blackborder detector to maintain state about detected borders.
Added simple unit test for blackborder processor.
This commit is contained in:
		@@ -1,3 +1,5 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					// Local-Hyperion includes
 | 
				
			||||||
#include "BlackBorderDetector.h"
 | 
					#include "BlackBorderDetector.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
BlackBorderDetector::BlackBorderDetector()
 | 
					BlackBorderDetector::BlackBorderDetector()
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										57
									
								
								libsrc/hyperion/BlackBorderProcessor.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								libsrc/hyperion/BlackBorderProcessor.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,57 @@
 | 
				
			|||||||
 | 
					#include "BlackBorderProcessor.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					BlackBorderProcessor::BlackBorderProcessor() :
 | 
				
			||||||
 | 
						_unknownSwitchCnt(600),
 | 
				
			||||||
 | 
						_borderSwitchCnt(50),
 | 
				
			||||||
 | 
						_detector(),
 | 
				
			||||||
 | 
						_currentBorder({BlackBorder::unknown, 0}),
 | 
				
			||||||
 | 
						_lastDetectedBorder({BlackBorder::unknown, 0}),
 | 
				
			||||||
 | 
						_consistentCnt(0)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					BlackBorder BlackBorderProcessor::getCurrentBorder() const
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return _currentBorder;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool BlackBorderProcessor::process(const RgbImage& image)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						const BlackBorder imageBorder = _detector.process(image);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (imageBorder.type == _lastDetectedBorder.type && imageBorder.size == _lastDetectedBorder.size)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							++_consistentCnt;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							_lastDetectedBorder = imageBorder;
 | 
				
			||||||
 | 
							_consistentCnt      = 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool borderChanged = false;
 | 
				
			||||||
 | 
						switch (_lastDetectedBorder.type)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
						case BlackBorder::none:
 | 
				
			||||||
 | 
							borderChanged = (_currentBorder.type != BlackBorder::none);
 | 
				
			||||||
 | 
							_currentBorder = _lastDetectedBorder;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case BlackBorder::horizontal:
 | 
				
			||||||
 | 
						case BlackBorder::vertical:
 | 
				
			||||||
 | 
							if (_consistentCnt == _borderSwitchCnt)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								_currentBorder = _lastDetectedBorder;
 | 
				
			||||||
 | 
								borderChanged = true;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case BlackBorder::unknown:
 | 
				
			||||||
 | 
							if (_consistentCnt == _unknownSwitchCnt)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								_currentBorder = _lastDetectedBorder;
 | 
				
			||||||
 | 
								borderChanged = true;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return borderChanged;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										30
									
								
								libsrc/hyperion/BlackBorderProcessor.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								libsrc/hyperion/BlackBorderProcessor.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,30 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Local Hyperion includes
 | 
				
			||||||
 | 
					#include "BlackBorderDetector.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class BlackBorderProcessor
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						BlackBorderProcessor();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						BlackBorder getCurrentBorder() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool process(const RgbImage& image);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						const unsigned _unknownSwitchCnt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						const unsigned _borderSwitchCnt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						BlackBorderDetector _detector;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						BlackBorder _currentBorder;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						BlackBorder _lastDetectedBorder;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						unsigned _consistentCnt;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -18,6 +18,7 @@ SET(Hyperion_HEADERS
 | 
				
			|||||||
		${CURRENT_SOURCE_DIR}/LedDeviceWs2801.h
 | 
							${CURRENT_SOURCE_DIR}/LedDeviceWs2801.h
 | 
				
			||||||
		${CURRENT_SOURCE_DIR}/LedDeviceTest.h
 | 
							${CURRENT_SOURCE_DIR}/LedDeviceTest.h
 | 
				
			||||||
		${CURRENT_SOURCE_DIR}/ImageToLedsMap.h
 | 
							${CURRENT_SOURCE_DIR}/ImageToLedsMap.h
 | 
				
			||||||
 | 
							${CURRENT_SOURCE_DIR}/BlackBorderProcessor.h
 | 
				
			||||||
		${CURRENT_SOURCE_DIR}/BlackBorderDetector.h
 | 
							${CURRENT_SOURCE_DIR}/BlackBorderDetector.h
 | 
				
			||||||
		${CURRENT_SOURCE_DIR}/ColorTransform.h
 | 
							${CURRENT_SOURCE_DIR}/ColorTransform.h
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@@ -32,6 +33,7 @@ SET(Hyperion_SOURCES
 | 
				
			|||||||
		${CURRENT_SOURCE_DIR}/LedDeviceWs2801.cpp
 | 
							${CURRENT_SOURCE_DIR}/LedDeviceWs2801.cpp
 | 
				
			||||||
		${CURRENT_SOURCE_DIR}/LedDeviceTest.cpp
 | 
							${CURRENT_SOURCE_DIR}/LedDeviceTest.cpp
 | 
				
			||||||
		${CURRENT_SOURCE_DIR}/ImageToLedsMap.cpp
 | 
							${CURRENT_SOURCE_DIR}/ImageToLedsMap.cpp
 | 
				
			||||||
 | 
							${CURRENT_SOURCE_DIR}/BlackBorderProcessor.cpp
 | 
				
			||||||
		${CURRENT_SOURCE_DIR}/BlackBorderDetector.cpp
 | 
							${CURRENT_SOURCE_DIR}/BlackBorderDetector.cpp
 | 
				
			||||||
		${CURRENT_SOURCE_DIR}/ColorTransform.cpp
 | 
							${CURRENT_SOURCE_DIR}/ColorTransform.cpp
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -34,3 +34,8 @@ add_executable(test_blackborderdetector
 | 
				
			|||||||
		TestBlackBorderDetector.cpp)
 | 
							TestBlackBorderDetector.cpp)
 | 
				
			||||||
target_link_libraries(test_blackborderdetector
 | 
					target_link_libraries(test_blackborderdetector
 | 
				
			||||||
		hyperion)
 | 
							hyperion)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					add_executable(test_blackborderprocessor
 | 
				
			||||||
 | 
							TestBlackBorderProcessor.cpp)
 | 
				
			||||||
 | 
					target_link_libraries(test_blackborderprocessor
 | 
				
			||||||
 | 
							hyperion)
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										143
									
								
								test/TestBlackBorderProcessor.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										143
									
								
								test/TestBlackBorderProcessor.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,143 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					// STL includes
 | 
				
			||||||
 | 
					#include <random>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Utils includes
 | 
				
			||||||
 | 
					#include <utils/RgbImage.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "hyperion/BlackBorderProcessor.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					RgbColor randomColor()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						const uint8_t randomRedValue   = uint8_t(rand() % (std::numeric_limits<uint8_t>::max() + 1));
 | 
				
			||||||
 | 
						const uint8_t randomGreenValue = uint8_t(rand() % (std::numeric_limits<uint8_t>::max() + 1));
 | 
				
			||||||
 | 
						const uint8_t randomBlueValue  = uint8_t(rand() % (std::numeric_limits<uint8_t>::max() + 1));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return {randomRedValue, randomGreenValue, randomBlueValue};
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					RgbImage createImage(unsigned width, unsigned height, unsigned topBorder, unsigned leftBorder)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						RgbImage image(width, height);
 | 
				
			||||||
 | 
						for (unsigned x=0; x<image.width(); ++x)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							for (unsigned y=0; y<image.height(); ++y)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								if (y < topBorder || x < leftBorder)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									image(x,y) = RgbColor::BLACK;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								else
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									image(x,y) = randomColor();
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return image;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int main()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						unsigned unknownCnt = 600;
 | 
				
			||||||
 | 
						unsigned borderCnt  = 50;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						BlackBorderProcessor processor;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Start with 'no border' detection
 | 
				
			||||||
 | 
						RgbImage noBorderImage = createImage(64, 64, 0, 0);
 | 
				
			||||||
 | 
						for (unsigned i=0; i<10; ++i)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							bool newBorder = processor.process(noBorderImage);
 | 
				
			||||||
 | 
							if (i == 0)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								// Switch to 'no border' should immediate
 | 
				
			||||||
 | 
								if (!newBorder)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									std::cerr << "Failed to detect 'no border' when required" << std::endl;
 | 
				
			||||||
 | 
									exit(EXIT_FAILURE);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								if (newBorder)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									std::cerr << "Incorrectly detected new border, when there in none" << std::endl;
 | 
				
			||||||
 | 
									exit(EXIT_FAILURE);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						// Verify that the border is indeed
 | 
				
			||||||
 | 
						if (processor.getCurrentBorder().type != BlackBorder::none)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							std::cerr << "Incorrectlty identified 'no border' (" << processor.getCurrentBorder().type << " != " << BlackBorder::none << ")" << std::endl;
 | 
				
			||||||
 | 
							exit(EXIT_FAILURE);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int borderSize = 12;
 | 
				
			||||||
 | 
						RgbImage horzImage = createImage(64, 64, borderSize, 0);
 | 
				
			||||||
 | 
						for (unsigned i=0; i<borderCnt*2; ++i)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							bool newBorder = processor.process(horzImage);
 | 
				
			||||||
 | 
							if (i == borderCnt)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								if (!newBorder)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									std::cerr << "Failed to detect 'horizontal border' when required after " << borderCnt << " images" << std::endl;
 | 
				
			||||||
 | 
									exit(EXIT_FAILURE);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								if (newBorder)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									std::cerr << "Incorrectly detected new border, when there in none" << std::endl;
 | 
				
			||||||
 | 
									exit(EXIT_FAILURE);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (processor.getCurrentBorder().type != BlackBorder::horizontal || processor.getCurrentBorder().size != borderSize)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							std::cerr << "Incorrectlty found 'horizontal border' (" << processor.getCurrentBorder().type << " != " << BlackBorder::horizontal << ")" << std::endl;
 | 
				
			||||||
 | 
							exit(EXIT_FAILURE);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Switch back (in one shot) to no border
 | 
				
			||||||
 | 
						if (!processor.process(noBorderImage) || (processor.getCurrentBorder().type != BlackBorder::none))
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							std::cerr << "Failed to switch back to 'no border' with one image" << std::endl;
 | 
				
			||||||
 | 
							exit(EXIT_FAILURE);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						RgbImage vertImage = createImage(64, 64, 0, borderSize);
 | 
				
			||||||
 | 
						for (unsigned i=0; i<borderCnt*2; ++i)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							bool newBorder = processor.process(vertImage);
 | 
				
			||||||
 | 
							if (i == borderCnt)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								if (!newBorder)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									std::cerr << "Failed to detect 'vertical border' when required after " << borderCnt << " images" << std::endl;
 | 
				
			||||||
 | 
									exit(EXIT_FAILURE);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								if (newBorder)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									std::cerr << "Incorrectly detected new border, when there in none" << std::endl;
 | 
				
			||||||
 | 
									exit(EXIT_FAILURE);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (processor.getCurrentBorder().type != BlackBorder::vertical || processor.getCurrentBorder().size != borderSize)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							std::cerr << "Incorrectlty found 'vertical border' (" << processor.getCurrentBorder().type << " != " << BlackBorder::horizontal << ")" << std::endl;
 | 
				
			||||||
 | 
							exit(EXIT_FAILURE);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Switch back (in one shot) to no border
 | 
				
			||||||
 | 
						assert(processor.process(noBorderImage));
 | 
				
			||||||
 | 
						assert(processor.getCurrentBorder().type == BlackBorder::none);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user