mirror of
				https://github.com/hyperion-project/hyperion.ng.git
				synced 2025-03-01 10:33:28 +00:00 
			
		
		
		
	Added config-schema of Hyperion as resource.
Added constructor to Hyperion using filename. Added config-filename as commandline parameter for hyperiond. Added implementation of blackborder detector. Added test for blackborder detector.
This commit is contained in:
		@@ -40,7 +40,6 @@ link_directories(${CMAKE_FIND_ROOT_PATH}/lib/arm-linux-gnueabihf)
 | 
			
		||||
 | 
			
		||||
configure_file(bin/install_hyperion.sh ${LIBRARY_OUTPUT_PATH} @ONLY)
 | 
			
		||||
configure_file(config/hyperion.config.json ${LIBRARY_OUTPUT_PATH} @ONLY)
 | 
			
		||||
configure_file(config/hyperion.schema.json ${LIBRARY_OUTPUT_PATH} @ONLY)
 | 
			
		||||
 | 
			
		||||
# Add the source/lib directories
 | 
			
		||||
add_subdirectory(dependencies)
 | 
			
		||||
 
 | 
			
		||||
@@ -23,6 +23,9 @@ class Hyperion : public QObject
 | 
			
		||||
public:
 | 
			
		||||
	static LedString createLedString(const Json::Value& ledsConfig);
 | 
			
		||||
 | 
			
		||||
	static Json::Value loadConfig(const std::string& configFile);
 | 
			
		||||
 | 
			
		||||
	Hyperion(const std::string& configFile);
 | 
			
		||||
	Hyperion(const Json::Value& jsonConfig);
 | 
			
		||||
 | 
			
		||||
	~Hyperion();
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										110
									
								
								libsrc/hyperion/BlackBorderDetector.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										110
									
								
								libsrc/hyperion/BlackBorderDetector.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,110 @@
 | 
			
		||||
#include "BlackBorderDetector.h"
 | 
			
		||||
 | 
			
		||||
BlackBorderDetector::BlackBorderDetector()
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
BlackBorder BlackBorderDetector::process(const RgbImage& image)
 | 
			
		||||
{
 | 
			
		||||
	int firstNonBlackPixelTop  = -1;
 | 
			
		||||
	int firstNonBlackPixelLeft = -1;
 | 
			
		||||
 | 
			
		||||
	for (unsigned x=0; x<image.width(); ++x)
 | 
			
		||||
	{
 | 
			
		||||
		const RgbColor& color = image(x, 0);
 | 
			
		||||
		if (!isBlack(color))
 | 
			
		||||
		{
 | 
			
		||||
			firstNonBlackPixelTop = x;
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	for (unsigned y=0; y<image.height(); ++y)
 | 
			
		||||
	{
 | 
			
		||||
		const RgbColor& color = image(0, y);
 | 
			
		||||
		if (!isBlack(color))
 | 
			
		||||
		{
 | 
			
		||||
			firstNonBlackPixelLeft = y;
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	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 || firstNonBlackPixelLeft > (int)(image.height()/2) )
 | 
			
		||||
		{
 | 
			
		||||
			// We don't know
 | 
			
		||||
			// B-B-B-B ... B-B-B-B
 | 
			
		||||
			// B +---- ... ----- ?
 | 
			
		||||
			// B |
 | 
			
		||||
			// B |
 | 
			
		||||
			// :
 | 
			
		||||
			// B |
 | 
			
		||||
			// B |
 | 
			
		||||
			// B |
 | 
			
		||||
			// B ?
 | 
			
		||||
 | 
			
		||||
			detectedBorder.type = BlackBorder::unknown;
 | 
			
		||||
			detectedBorder.size = -1;
 | 
			
		||||
		}
 | 
			
		||||
		else //(firstNonBlackPixelLeft > 0 && firstNonBlackPixelLeft < image.height()/2)
 | 
			
		||||
		{
 | 
			
		||||
			// Border at top of screen
 | 
			
		||||
			// B-B-B-B ... B-B-B-B
 | 
			
		||||
			// B +---- ... ----- ?
 | 
			
		||||
			// C |
 | 
			
		||||
			// ? |
 | 
			
		||||
			// :
 | 
			
		||||
 | 
			
		||||
			detectedBorder.type = BlackBorder::horizontal;
 | 
			
		||||
			detectedBorder.size = firstNonBlackPixelLeft;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	else // (firstNonBlackPixelTop > 0)
 | 
			
		||||
	{
 | 
			
		||||
		if (firstNonBlackPixelTop < int(image.width()/2) && firstNonBlackPixelLeft < 0)
 | 
			
		||||
		{
 | 
			
		||||
			// Border at left of screen
 | 
			
		||||
			// B-B-C-? ...
 | 
			
		||||
			// B +---- ... ----- ?
 | 
			
		||||
			// B |
 | 
			
		||||
			// B |
 | 
			
		||||
			// :
 | 
			
		||||
			// B |
 | 
			
		||||
			// B |
 | 
			
		||||
			// B |
 | 
			
		||||
			// B ?
 | 
			
		||||
 | 
			
		||||
			detectedBorder.type = BlackBorder::vertical;
 | 
			
		||||
			detectedBorder.size = firstNonBlackPixelTop;
 | 
			
		||||
		}
 | 
			
		||||
		else //(firstNonBlackPixelTop > int(mage.width()/2) || firstNonBlackPixelLeft > 0)
 | 
			
		||||
		{
 | 
			
		||||
			// No black border
 | 
			
		||||
			// B-B-C-? ...
 | 
			
		||||
			// B +----
 | 
			
		||||
			// C |
 | 
			
		||||
			// ? |
 | 
			
		||||
			// :
 | 
			
		||||
 | 
			
		||||
			detectedBorder.type = BlackBorder::none;
 | 
			
		||||
			detectedBorder.size = -1;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return detectedBorder;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										38
									
								
								libsrc/hyperion/BlackBorderDetector.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								libsrc/hyperion/BlackBorderDetector.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,38 @@
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
// Utils includes
 | 
			
		||||
#include <utils/RgbImage.h>
 | 
			
		||||
 | 
			
		||||
struct BlackBorder
 | 
			
		||||
{
 | 
			
		||||
	enum Type
 | 
			
		||||
	{
 | 
			
		||||
		none,
 | 
			
		||||
		horizontal,
 | 
			
		||||
		vertical,
 | 
			
		||||
		unknown
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	Type type;
 | 
			
		||||
	int size;
 | 
			
		||||
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class BlackBorderDetector
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
	BlackBorderDetector();
 | 
			
		||||
 | 
			
		||||
	BlackBorder process(const RgbImage& image);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
 | 
			
		||||
	inline bool isBlack(const RgbColor& color)
 | 
			
		||||
	{
 | 
			
		||||
		return RgbColor::BLACK == color;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
};
 | 
			
		||||
@@ -18,6 +18,7 @@ SET(Hyperion_HEADERS
 | 
			
		||||
		${CURRENT_SOURCE_DIR}/LedDeviceWs2801.h
 | 
			
		||||
		${CURRENT_SOURCE_DIR}/LedDeviceTest.h
 | 
			
		||||
		${CURRENT_SOURCE_DIR}/ImageToLedsMap.h
 | 
			
		||||
		${CURRENT_SOURCE_DIR}/BlackBorderDetector.h
 | 
			
		||||
		${CURRENT_SOURCE_DIR}/ColorTransform.h
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
@@ -31,16 +32,24 @@ SET(Hyperion_SOURCES
 | 
			
		||||
		${CURRENT_SOURCE_DIR}/LedDeviceWs2801.cpp
 | 
			
		||||
		${CURRENT_SOURCE_DIR}/LedDeviceTest.cpp
 | 
			
		||||
		${CURRENT_SOURCE_DIR}/ImageToLedsMap.cpp
 | 
			
		||||
		${CURRENT_SOURCE_DIR}/BlackBorderDetector.cpp
 | 
			
		||||
		${CURRENT_SOURCE_DIR}/ColorTransform.cpp
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
set(Hyperion_RESOURCES
 | 
			
		||||
		${CURRENT_SOURCE_DIR}/resource.qrc
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
QT4_WRAP_CPP(Hyperion_HEADERS_MOC ${Hyperion_QT_HEADERS})
 | 
			
		||||
 | 
			
		||||
qt4_add_resources(Hyperion_RESOURCES_RCC ${Hyperion_RESOURCES} OPTIONS "-no-compress")
 | 
			
		||||
 | 
			
		||||
add_library(hyperion
 | 
			
		||||
		${Hyperion_HEADERS}
 | 
			
		||||
		${Hyperion_QT_HEADERS}
 | 
			
		||||
		${Hyperion_HEADERS_MOC}
 | 
			
		||||
		${Hyperion_SOURCES}
 | 
			
		||||
		${Hyperion_RESOURCES_RCC}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
target_link_libraries(hyperion
 | 
			
		||||
 
 | 
			
		||||
@@ -1,8 +1,7 @@
 | 
			
		||||
 | 
			
		||||
// Syslog include
 | 
			
		||||
#include <syslog.h>
 | 
			
		||||
 | 
			
		||||
// QT includes
 | 
			
		||||
#include <QDateTime>
 | 
			
		||||
#include <QResource>
 | 
			
		||||
 | 
			
		||||
// JsonSchema include
 | 
			
		||||
#include <utils/jsonschema/JsonFactory.h>
 | 
			
		||||
@@ -75,6 +74,33 @@ LedString Hyperion::createLedString(const Json::Value& ledsConfig)
 | 
			
		||||
	return ledString;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Json::Value Hyperion::loadConfig(const std::string& configFile)
 | 
			
		||||
{
 | 
			
		||||
	// read the json schema from the resource
 | 
			
		||||
	QResource schemaData(":/hyperion.schema.json");
 | 
			
		||||
	assert(schemaData.isValid());
 | 
			
		||||
 | 
			
		||||
	Json::Reader jsonReader;
 | 
			
		||||
	Json::Value schemaJson;
 | 
			
		||||
	if (!jsonReader.parse(reinterpret_cast<const char *>(schemaData.data()), reinterpret_cast<const char *>(schemaData.data()) + schemaData.size(), schemaJson, false))
 | 
			
		||||
	{
 | 
			
		||||
		throw std::runtime_error("Schema error: " + jsonReader.getFormattedErrorMessages())	;
 | 
			
		||||
	}
 | 
			
		||||
	JsonSchemaChecker schemaChecker;
 | 
			
		||||
	schemaChecker.setSchema(schemaJson);
 | 
			
		||||
 | 
			
		||||
	const Json::Value jsonConfig = JsonFactory::readJson(configFile);
 | 
			
		||||
	schemaChecker.validate(jsonConfig);
 | 
			
		||||
 | 
			
		||||
	return jsonConfig;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Hyperion::Hyperion(const std::string& configFile) :
 | 
			
		||||
	Hyperion(loadConfig(configFile))
 | 
			
		||||
{
 | 
			
		||||
	// empty
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Hyperion::Hyperion(const Json::Value &jsonConfig) :
 | 
			
		||||
	mLedString(createLedString(jsonConfig["leds"])),
 | 
			
		||||
	mRedTransform(  createColorTransform(jsonConfig["color"]["red"])),
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										5
									
								
								libsrc/hyperion/resource.qrc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								libsrc/hyperion/resource.qrc
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
			
		||||
<RCC>
 | 
			
		||||
    <qresource prefix="/">
 | 
			
		||||
        <file>hyperion.schema.json</file>
 | 
			
		||||
    </qresource>
 | 
			
		||||
</RCC>
 | 
			
		||||
@@ -20,21 +20,17 @@ int main(int argc, char** argv)
 | 
			
		||||
	QCoreApplication app(argc, argv);
 | 
			
		||||
	std::cout << "QCoreApplication initialised" << std::endl;
 | 
			
		||||
 | 
			
		||||
	// Select config and schema file
 | 
			
		||||
	//const std::string homeDir = getenv("RASPILIGHT_HOME");
 | 
			
		||||
	const std::string schemaFile = "hyperion.schema.json";
 | 
			
		||||
	const std::string configFile = "hyperion.config.json";
 | 
			
		||||
 | 
			
		||||
	// Load configuration and check against the schema at the same time
 | 
			
		||||
	Json::Value config;
 | 
			
		||||
	if (JsonFactory::load(schemaFile, configFile, config) < 0)
 | 
			
		||||
	if (argc < 2)
 | 
			
		||||
	{
 | 
			
		||||
		std::cerr << "UNABLE TO LOAD CONFIGURATION" << std::endl;
 | 
			
		||||
		return -1;
 | 
			
		||||
		std::cout << "Missing required configuration file. Usage:" << std::endl;
 | 
			
		||||
		std::cout << "hyperiond [config.file]" << std::endl;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
	std::cout << "Configuration loaded from: " << configFile << std::endl;
 | 
			
		||||
 | 
			
		||||
	Hyperion hyperion(config);
 | 
			
		||||
	const std::string configFile = argv[2];
 | 
			
		||||
	std::cout << "Selected configuration file: " << configFile.c_str() << std::endl;
 | 
			
		||||
 | 
			
		||||
	Hyperion hyperion(configFile);
 | 
			
		||||
	std::cout << "Hyperion created and initialised" << std::endl;
 | 
			
		||||
 | 
			
		||||
	DispmanxWrapper dispmanx(64, 64, 10, &hyperion);
 | 
			
		||||
 
 | 
			
		||||
@@ -29,3 +29,8 @@ target_link_libraries(test_image2ledsmap
 | 
			
		||||
		hyperion)
 | 
			
		||||
 | 
			
		||||
add_subdirectory(dispmanx2png)
 | 
			
		||||
 | 
			
		||||
add_executable(test_blackborderdetector
 | 
			
		||||
		TestBlackBorderDetector.cpp)
 | 
			
		||||
target_link_libraries(test_blackborderdetector
 | 
			
		||||
		hyperion)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										120
									
								
								test/TestBlackBorderDetector.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										120
									
								
								test/TestBlackBorderDetector.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,120 @@
 | 
			
		||||
 | 
			
		||||
// STL includes
 | 
			
		||||
#include <random>
 | 
			
		||||
 | 
			
		||||
// Hyperion includes
 | 
			
		||||
#include "hyperion/BlackBorderDetector.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 TC_NO_BORDER()
 | 
			
		||||
{
 | 
			
		||||
	int result = 0;
 | 
			
		||||
 | 
			
		||||
	BlackBorderDetector detector;
 | 
			
		||||
 | 
			
		||||
	{
 | 
			
		||||
		RgbImage image = createImage(64, 64, 0, 0);
 | 
			
		||||
		BlackBorder border = detector.process(image);
 | 
			
		||||
		if (border.type != BlackBorder::none)
 | 
			
		||||
		{
 | 
			
		||||
			std::cerr << "Failed to correctly detect no border" << std::endl;
 | 
			
		||||
			result = -1;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int TC_TOP_BORDER()
 | 
			
		||||
{
 | 
			
		||||
	int result = 0;
 | 
			
		||||
 | 
			
		||||
	BlackBorderDetector detector;
 | 
			
		||||
 | 
			
		||||
	{
 | 
			
		||||
		RgbImage image = createImage(64, 64, 12, 0);
 | 
			
		||||
		BlackBorder border = detector.process(image);
 | 
			
		||||
		if (border.type != BlackBorder::horizontal || border.size != 12)
 | 
			
		||||
		{
 | 
			
		||||
			std::cerr << "Failed to correctly detect horizontal border with correct size" << std::endl;
 | 
			
		||||
			result = -1;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int TC_LEFT_BORDER()
 | 
			
		||||
{
 | 
			
		||||
	int result = 0;
 | 
			
		||||
 | 
			
		||||
	BlackBorderDetector detector;
 | 
			
		||||
 | 
			
		||||
	{
 | 
			
		||||
		RgbImage image = createImage(64, 64, 0, 12);
 | 
			
		||||
		BlackBorder border = detector.process(image);
 | 
			
		||||
		if (border.type != BlackBorder::vertical || border.size != 12)
 | 
			
		||||
		{
 | 
			
		||||
			std::cerr << "Failed to detected vertical border with correct size" << std::endl;
 | 
			
		||||
			result = -1;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int TC_UNKNOWN_BORDER()
 | 
			
		||||
{
 | 
			
		||||
	int result = 0;
 | 
			
		||||
 | 
			
		||||
	BlackBorderDetector detector;
 | 
			
		||||
 | 
			
		||||
	{
 | 
			
		||||
		RgbImage image = createImage(64, 64, 12, 12);
 | 
			
		||||
		BlackBorder border = detector.process(image);
 | 
			
		||||
		if (border.type != BlackBorder::unknown)
 | 
			
		||||
		{
 | 
			
		||||
			std::cerr << "Failed to detected unknown border" << std::endl;
 | 
			
		||||
			result = -1;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int main()
 | 
			
		||||
{
 | 
			
		||||
	TC_NO_BORDER();
 | 
			
		||||
	TC_TOP_BORDER();
 | 
			
		||||
	TC_LEFT_BORDER();
 | 
			
		||||
	TC_UNKNOWN_BORDER();
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user