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:
T. van der Zwan 2013-08-21 14:25:27 +00:00
parent 5010b9ce8e
commit 240b118ce9
11 changed files with 327 additions and 16 deletions

View File

@ -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)

View File

@ -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();

View 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;
}

View 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;
}
};

View File

@ -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

View File

@ -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"])),

View File

@ -0,0 +1,5 @@
<RCC>
<qresource prefix="/">
<file>hyperion.schema.json</file>
</qresource>
</RCC>

View File

@ -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);

View File

@ -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)

View 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;
}