mirror of
https://github.com/hyperion-project/hyperion.ng.git
synced 2023-10-10 13:36:59 +02: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:
parent
5010b9ce8e
commit
240b118ce9
@ -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(bin/install_hyperion.sh ${LIBRARY_OUTPUT_PATH} @ONLY)
|
||||||
configure_file(config/hyperion.config.json ${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 the source/lib directories
|
||||||
add_subdirectory(dependencies)
|
add_subdirectory(dependencies)
|
||||||
|
@ -23,6 +23,9 @@ class Hyperion : public QObject
|
|||||||
public:
|
public:
|
||||||
static LedString createLedString(const Json::Value& ledsConfig);
|
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(const Json::Value& jsonConfig);
|
||||||
|
|
||||||
~Hyperion();
|
~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}/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}/BlackBorderDetector.h
|
||||||
${CURRENT_SOURCE_DIR}/ColorTransform.h
|
${CURRENT_SOURCE_DIR}/ColorTransform.h
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -31,16 +32,24 @@ 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}/BlackBorderDetector.cpp
|
||||||
${CURRENT_SOURCE_DIR}/ColorTransform.cpp
|
${CURRENT_SOURCE_DIR}/ColorTransform.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
|
set(Hyperion_RESOURCES
|
||||||
|
${CURRENT_SOURCE_DIR}/resource.qrc
|
||||||
|
)
|
||||||
|
|
||||||
QT4_WRAP_CPP(Hyperion_HEADERS_MOC ${Hyperion_QT_HEADERS})
|
QT4_WRAP_CPP(Hyperion_HEADERS_MOC ${Hyperion_QT_HEADERS})
|
||||||
|
|
||||||
|
qt4_add_resources(Hyperion_RESOURCES_RCC ${Hyperion_RESOURCES} OPTIONS "-no-compress")
|
||||||
|
|
||||||
add_library(hyperion
|
add_library(hyperion
|
||||||
${Hyperion_HEADERS}
|
${Hyperion_HEADERS}
|
||||||
${Hyperion_QT_HEADERS}
|
${Hyperion_QT_HEADERS}
|
||||||
${Hyperion_HEADERS_MOC}
|
${Hyperion_HEADERS_MOC}
|
||||||
${Hyperion_SOURCES}
|
${Hyperion_SOURCES}
|
||||||
|
${Hyperion_RESOURCES_RCC}
|
||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(hyperion
|
target_link_libraries(hyperion
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
|
|
||||||
// Syslog include
|
// QT includes
|
||||||
#include <syslog.h>
|
|
||||||
|
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
|
#include <QResource>
|
||||||
|
|
||||||
// JsonSchema include
|
// JsonSchema include
|
||||||
#include <utils/jsonschema/JsonFactory.h>
|
#include <utils/jsonschema/JsonFactory.h>
|
||||||
@ -75,6 +74,33 @@ LedString Hyperion::createLedString(const Json::Value& ledsConfig)
|
|||||||
return ledString;
|
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) :
|
Hyperion::Hyperion(const Json::Value &jsonConfig) :
|
||||||
mLedString(createLedString(jsonConfig["leds"])),
|
mLedString(createLedString(jsonConfig["leds"])),
|
||||||
mRedTransform( createColorTransform(jsonConfig["color"]["red"])),
|
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);
|
QCoreApplication app(argc, argv);
|
||||||
std::cout << "QCoreApplication initialised" << std::endl;
|
std::cout << "QCoreApplication initialised" << std::endl;
|
||||||
|
|
||||||
// Select config and schema file
|
if (argc < 2)
|
||||||
//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)
|
|
||||||
{
|
{
|
||||||
std::cerr << "UNABLE TO LOAD CONFIGURATION" << std::endl;
|
std::cout << "Missing required configuration file. Usage:" << std::endl;
|
||||||
return -1;
|
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;
|
std::cout << "Hyperion created and initialised" << std::endl;
|
||||||
|
|
||||||
DispmanxWrapper dispmanx(64, 64, 10, &hyperion);
|
DispmanxWrapper dispmanx(64, 64, 10, &hyperion);
|
||||||
|
@ -29,3 +29,8 @@ target_link_libraries(test_image2ledsmap
|
|||||||
hyperion)
|
hyperion)
|
||||||
|
|
||||||
add_subdirectory(dispmanx2png)
|
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;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user