initial import
commit
8c21e7ac6a
|
@ -0,0 +1,5 @@
|
||||||
|
build
|
||||||
|
.cproject
|
||||||
|
.project
|
||||||
|
.settings/
|
||||||
|
c++/html
|
|
@ -0,0 +1,2 @@
|
||||||
|
filter=-build/include_subdir,-whitespace/line_length
|
||||||
|
root=cpp
|
|
@ -0,0 +1,9 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2022 GrumyDeveloper https://contentnation.net/en/grumpydevelop/
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@ -0,0 +1,4 @@
|
||||||
|
# Path animator
|
||||||
|
|
||||||
|
Source code for the Path animator framework on [the project page](https://contentnation.net/en/grumpydevelop/pathanimator).
|
||||||
|
Initial implementation in C++ running on Linux, testing needs to be done if it can be in-browser via Javascript to make it cross plattform client only.
|
|
@ -0,0 +1,41 @@
|
||||||
|
cmake_minimum_required(VERSION 3.0.0)
|
||||||
|
set(CMAKE_BUILD_TYPE None)
|
||||||
|
set(config release CACHE STRING "build mode <debug|native|generic>")
|
||||||
|
cmake_policy(SET CMP0017 NEW)
|
||||||
|
project(pathanimator)
|
||||||
|
|
||||||
|
enable_testing()
|
||||||
|
if (config STREQUAL "debug")
|
||||||
|
message("building debug version")
|
||||||
|
add_definitions(-Wall -Wextra -O0 -g)
|
||||||
|
set(CMAKE_EXE_LINKER_FLAGS "-O0 -g")
|
||||||
|
set(CMAKE_SHARED_LINKER_FLAGS "-O0 -g")
|
||||||
|
set(CMAKE_MODULE_LINKER_FLAGS "-O0 -g")
|
||||||
|
elseif (config STREQUAL "native")
|
||||||
|
message("building release version optimized for local CPU")
|
||||||
|
add_definitions(-Wall -Wextra -O3 -march=native -mtune=native)
|
||||||
|
set(CMAKE_EXE_LINKER_FLAGS "-O3 -march=native -mtune=native")
|
||||||
|
set(CMAKE_SHARED_LINKER_FLAGS "-O3 -march=native -mtune=native")
|
||||||
|
set(CMAKE_MODULE_LINKER_FLAGS "-O3 -march=native -mtune=native")
|
||||||
|
message("building generic release version")
|
||||||
|
add_definitions(-Wall -Wextra -O3)
|
||||||
|
set(CMAKE_EXE_LINKER_FLAGS "-O3 ")
|
||||||
|
set(CMAKE_SHARED_LINKER_FLAGS "-O3 ")
|
||||||
|
set(CMAKE_MODULE_LINKER_FLAGS "-O3 ")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
add_definitions(-DPROJECT_ROOT="${PROJECT_SOURCE_DIR}")
|
||||||
|
add_definitions(-std=c++11)
|
||||||
|
set (CMAKE_CXX_STANDARD 11)
|
||||||
|
set (CMAKE_C_STANDARD 11)
|
||||||
|
|
||||||
|
set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/)
|
||||||
|
find_package(OpenImageIO REQUIRED)
|
||||||
|
|
||||||
|
include_directories (
|
||||||
|
${CMAKE_SOURCE_DIR}/
|
||||||
|
)
|
||||||
|
add_subdirectory(algorithm)
|
||||||
|
|
||||||
|
add_executable(pathanimator init.cpp main.cpp image.cpp)
|
||||||
|
target_link_libraries(pathanimator algorithms OpenImageIO)
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1 @@
|
||||||
|
add_library(algorithms distancepath.cpp)
|
|
@ -0,0 +1,22 @@
|
||||||
|
# Algrithm descriptions
|
||||||
|
## Distance Path
|
||||||
|
This algorithm uses a simple distance calculation based from one or more start points.
|
||||||
|
|
||||||
|
1. Initialization
|
||||||
|
* The start points are added to the "to process" queue.
|
||||||
|
* The distance values on all pixels are set to m_maxDistance on start.
|
||||||
|
2. Main loop
|
||||||
|
* Each point in the "to process" queue is taken and it's value (distance).
|
||||||
|
* Each surrounding pixel takes the last distance (the center) and adds the distance given by the parameters m_weighBlock and m_weightPath.
|
||||||
|
The input image selects the weight from the two parameters, a 0 (black) pixel takes 100% of the block value, a (255) white pixel
|
||||||
|
is 100% path weight.
|
||||||
|
* If this distance is smaller than the previous pixel that was calulated, replace it and add the pixel to the next list of pixel to be processed.
|
||||||
|
* After the iteration is done, clear the process queue and swap with the next queue and repeat until the next queue is empty or the hard limit of 10.000 iterations is met.
|
||||||
|
3. Postprocessing
|
||||||
|
* After the raw distances are calculated, the actual max distance is found.
|
||||||
|
* The raw map (floating ponts) is mapped down to a 16 bit image and the distance is saved in the red channel,
|
||||||
|
* the iteration where the pixel was set is in the green channel
|
||||||
|
* the blue channel is a mask if the pixel was seen as a path (65535) or as a block (0).
|
||||||
|
The m_threshhold value sets the point where a path becomes a block.
|
||||||
|
Setting the threshhold allows some cheating. You can add an path between areas with a gray value, the algorithm uses it to calculate
|
||||||
|
distance and as a path to other ares, but shows it as a block in the blue channel.
|
|
@ -0,0 +1,28 @@
|
||||||
|
/// \file algorithm/algorithm.h
|
||||||
|
/// \copyright 2022 Sascha Nitsch
|
||||||
|
/// Licence under MIT license
|
||||||
|
/// \brief declaration of the Algorithm class
|
||||||
|
|
||||||
|
#ifndef ALGORITHM_ALGORITHM_H_
|
||||||
|
#define ALGORITHM_ALGORITHM_H_
|
||||||
|
|
||||||
|
// system includes
|
||||||
|
#include <inttypes.h>
|
||||||
|
// own includes
|
||||||
|
#include "../image.h"
|
||||||
|
|
||||||
|
/// namespace for different time generation algorithms
|
||||||
|
namespace Algorithm {
|
||||||
|
/// \brief base class for the different time generation algorithms
|
||||||
|
class Algorithm {
|
||||||
|
public:
|
||||||
|
/// \brief destructor
|
||||||
|
virtual ~Algorithm() {}
|
||||||
|
/// \brief process images
|
||||||
|
/// \param input input image
|
||||||
|
/// \param output output image
|
||||||
|
/// \return 0 if ok, != 0 on error
|
||||||
|
virtual int8_t process(Image* input, Image* output) = 0;
|
||||||
|
};
|
||||||
|
} // namespace Algorithm
|
||||||
|
#endif // ALGORITHM_ALGORITHM_H_
|
|
@ -0,0 +1,133 @@
|
||||||
|
/// \file algorithm/distancepath.cpp
|
||||||
|
/// \copyright 2022 Sascha Nitsch
|
||||||
|
/// Licenced under MIT license
|
||||||
|
/// \brief implementation of the DistancePath class
|
||||||
|
|
||||||
|
|
||||||
|
// system includes
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
// own includes
|
||||||
|
#include "distancepath.h"
|
||||||
|
|
||||||
|
namespace Algorithm {
|
||||||
|
|
||||||
|
DistancePath::DistancePath(int argc, const char* argv[]) {
|
||||||
|
if (argc < 6) {
|
||||||
|
printf("DistancePath needs min 6 arguments <weight for traversalable pixel> <weight for blocked pixel> <Threshhold to mark as traversable> <max Distance> <StartX> <StartY> [<StartX> <StartY>] ...");
|
||||||
|
} else {
|
||||||
|
m_weightPath = atof(argv[0]);
|
||||||
|
m_weightBlock = atof(argv[1]);
|
||||||
|
m_threshhold = atoi(argv[2]);
|
||||||
|
m_maxDistance = atof(argv[3]);
|
||||||
|
for (uint8_t i = 4; i < argc; i+=2) {
|
||||||
|
m_queue1.push_back((uint32_t)(atoi(argv[i]) << 16) + atoi(argv[i + 1]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DistancePath::~DistancePath() {
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void DistancePath::processPixel(uint8_t* inRAW, float* outRow, uint16_t x, uint16_t y, float lastValue, uint16_t width, std::list<uint32_t>* next, uint16_t* outPixels, uint16_t iteration) {
|
||||||
|
float *oR = &outRow[x];
|
||||||
|
uint32_t offset = (y * width + x) * 3;
|
||||||
|
float avg = 255 - (0.3333 * (inRAW[offset] + inRAW[offset + 1] + inRAW[offset + 2]));
|
||||||
|
float newValue = lastValue + avg * m_weightBlock + (255.0 - avg) * m_weightPath;
|
||||||
|
if (newValue > m_maxDistance) newValue = m_maxDistance;
|
||||||
|
if (newValue < *oR) {
|
||||||
|
next->push_back((x << 16) + y);
|
||||||
|
outPixels[offset + 1] = iteration;
|
||||||
|
*oR = newValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
inline void DistancePath::processRow(uint8_t* inRAW, float* outRAW, uint16_t x, uint16_t y, float lastValue, uint16_t width, std::list<uint32_t>* next, uint16_t* outPixels, uint16_t iteration) {
|
||||||
|
float* outRow = &outRAW[y * width];
|
||||||
|
if (x > 0) {
|
||||||
|
processPixel(inRAW, outRow, x - 1, y, lastValue, width, next, outPixels, iteration);
|
||||||
|
}
|
||||||
|
processPixel(inRAW, outRow, x, y, lastValue, width, next, outPixels, iteration);
|
||||||
|
if (x < width - 1) {
|
||||||
|
processPixel(inRAW, outRow, x + 1, y, lastValue, width, next, outPixels, iteration);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int8_t DistancePath::process(Image* input, Image* output) {
|
||||||
|
std::list<uint32_t> queue2;
|
||||||
|
std::list<uint32_t>* last = &m_queue1;
|
||||||
|
std::list<uint32_t>* next = &queue2;
|
||||||
|
uint16_t width = input->getWidth();
|
||||||
|
uint16_t height = input->getHeight();
|
||||||
|
uint8_t* inRAW = input->getPixels8();
|
||||||
|
uint32_t end = width * height;
|
||||||
|
// allocate output storage and set to m_maxDistance
|
||||||
|
float* outRAW = reinterpret_cast<float*>(malloc(width * height * sizeof(float)));
|
||||||
|
for (uint32_t i = 0; i < end; ++i) {
|
||||||
|
outRAW[i] = m_maxDistance;
|
||||||
|
}
|
||||||
|
// set start pixels to distance of 0
|
||||||
|
uint16_t* outPixels = output->getPixels16();
|
||||||
|
for (uint32_t coordinate : m_queue1) {
|
||||||
|
uint16_t x = coordinate >> 16;
|
||||||
|
uint16_t y = coordinate & 0xFFFFFFFF;
|
||||||
|
outRAW[(width * y + x)] = 0;
|
||||||
|
}
|
||||||
|
uint16_t iteration = 1;
|
||||||
|
do {
|
||||||
|
// process pixel from last time
|
||||||
|
for (uint32_t coordinate : *last) {
|
||||||
|
uint16_t x = coordinate >> 16;
|
||||||
|
uint16_t y = coordinate & 0xFFFFFFFF;
|
||||||
|
float lastValue = outRAW[y * width + x];
|
||||||
|
if (y > 0) { // process row on top
|
||||||
|
processRow(inRAW, outRAW, x, y-1, lastValue, width, next, outPixels, iteration);
|
||||||
|
}
|
||||||
|
processRow(inRAW, outRAW, x, y, lastValue, width, next, outPixels, iteration);
|
||||||
|
if (y < height - 1) { // process row on bottom
|
||||||
|
processRow(inRAW, outRAW, x, y+1, lastValue, width, next, outPixels, iteration);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
++iteration;
|
||||||
|
// clear out old list
|
||||||
|
last->clear();
|
||||||
|
// swap list to get new input queue
|
||||||
|
std::swap(last, next);
|
||||||
|
if (iteration > 10000) break;
|
||||||
|
} while (next->size() > 0);
|
||||||
|
|
||||||
|
printf("iterations: %i\n", iteration);
|
||||||
|
// find max value
|
||||||
|
float max = 0;
|
||||||
|
uint16_t threshhold = m_threshhold * 3; // multiply by 3 here saves many division from sum to average in the loops below
|
||||||
|
|
||||||
|
// could be optimized, but it is only run once for every pixel
|
||||||
|
for (uint32_t i = 0; i < end; ++i) {
|
||||||
|
uint32_t offset = i * 3;
|
||||||
|
uint16_t sum = (inRAW[offset] + inRAW[offset + 1] + inRAW[offset + 2]);
|
||||||
|
// only update max if it is larger than previous, but still smaller than our max distance and larger as the threshhold (visible path cheat)
|
||||||
|
if (outRAW[i] > max && outRAW[i] < m_maxDistance && (sum > threshhold)) max = outRAW[i];
|
||||||
|
}
|
||||||
|
float iterMult = 65535.0 / iteration; // multiplicator to map iteration from 0 to 65535
|
||||||
|
max = 65535.0 / max; // results in 0 ... 65535 range
|
||||||
|
// write result to output
|
||||||
|
uint32_t offset = 0;
|
||||||
|
for (uint32_t i = 0; i < end; ++i) {
|
||||||
|
uint16_t sum = (inRAW[offset] + inRAW[offset + 1] + inRAW[offset + 2]);
|
||||||
|
if (sum > threshhold) {
|
||||||
|
outPixels[offset] = outRAW[i] * max; // red = distance
|
||||||
|
outPixels[offset + 1] = iterMult * outPixels[offset + 1]; // green = iteration
|
||||||
|
outPixels[offset + 2] = 65535; // blue= a pathable pixel
|
||||||
|
} else {
|
||||||
|
outPixels[offset] = 0;
|
||||||
|
outPixels[offset + 1] = 0;
|
||||||
|
outPixels[offset + 2] = 0;
|
||||||
|
}
|
||||||
|
offset += 3;
|
||||||
|
}
|
||||||
|
free(outRAW);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} // namespace Algorithm
|
|
@ -0,0 +1,75 @@
|
||||||
|
/// \file algorithm/distancepath.h
|
||||||
|
/// \copyright 2022 Sascha Nitsch
|
||||||
|
/// Licenced under MIT license
|
||||||
|
/// \brief declaration of the DistancePath class
|
||||||
|
|
||||||
|
#ifndef ALGORITHM_DISTANCEPATH_H_
|
||||||
|
#define ALGORITHM_DISTANCEPATH_H_
|
||||||
|
// system includes
|
||||||
|
#include <list>
|
||||||
|
|
||||||
|
// own includes
|
||||||
|
#include "algorithm.h"
|
||||||
|
|
||||||
|
// forward declaration
|
||||||
|
class Image;
|
||||||
|
|
||||||
|
namespace Algorithm {
|
||||||
|
|
||||||
|
/// \brief calculate value based on distance to start point
|
||||||
|
/// for a long description, see README.md
|
||||||
|
class DistancePath : public Algorithm {
|
||||||
|
public:
|
||||||
|
/// \brief constructor
|
||||||
|
/// \param argc number of arguments
|
||||||
|
/// \param argv arguments
|
||||||
|
DistancePath(int argc, const char* argv[]);
|
||||||
|
|
||||||
|
/// \brief destructor
|
||||||
|
~DistancePath();
|
||||||
|
|
||||||
|
/// \brief process images
|
||||||
|
/// \param input input image
|
||||||
|
/// \param output output image
|
||||||
|
/// \return 0 if ok, != 0 on error
|
||||||
|
int8_t process(Image* input, Image* output);
|
||||||
|
|
||||||
|
private:
|
||||||
|
/// \brief do actual calculation on pixel
|
||||||
|
/// \param inRAW pointer to raw image input
|
||||||
|
/// \param outRow pointer to current row in output
|
||||||
|
/// \param x x coordinate
|
||||||
|
/// \param y y coordinate
|
||||||
|
/// \param lastValue last value from source pixel
|
||||||
|
/// \param width image width
|
||||||
|
/// \param next list to put new pixel to
|
||||||
|
/// \param outPixels pointer to output pixel array
|
||||||
|
/// \param iteration current iteration number
|
||||||
|
inline void processPixel(uint8_t* inRAW, float* outRow, uint16_t x, uint16_t y, float lastValue, uint16_t width, std::list<uint32_t>* next, uint16_t* outPixels, uint16_t iteration);
|
||||||
|
|
||||||
|
/// \brief do actual calculation on pixel row
|
||||||
|
/// \param inRAW pointer to raw image input
|
||||||
|
/// \param outRAW pointer to output
|
||||||
|
/// \param x x coordinate
|
||||||
|
/// \param y y coordinate
|
||||||
|
/// \param lastValue last value from source pixel
|
||||||
|
/// \param width image width
|
||||||
|
/// \param next list to put new pixel to
|
||||||
|
/// \param outPixels pointer to output pixel array
|
||||||
|
/// \param iteration current iteration number
|
||||||
|
inline void processRow(uint8_t* inRAW, float* outRAW, uint16_t x, uint16_t y, float lastValue, uint16_t width, std::list<uint32_t>* next, uint16_t* outPixels, uint16_t iteration);
|
||||||
|
|
||||||
|
/// weight for pathable neighbour
|
||||||
|
float m_weightPath;
|
||||||
|
/// weight for blocked neighbour
|
||||||
|
float m_weightBlock;
|
||||||
|
/// top cap
|
||||||
|
float m_maxDistance;
|
||||||
|
/// threshhold to mark pixel as traversable in output
|
||||||
|
uint8_t m_threshhold;
|
||||||
|
/// queue of pixels to process
|
||||||
|
std::list<uint32_t> m_queue1;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Algorithm
|
||||||
|
#endif // ALGORITHM_DISTANCEPATH_H_
|
|
@ -0,0 +1,53 @@
|
||||||
|
/// \file image.cpp
|
||||||
|
/// \copyright 2022 Sascha Nitsch
|
||||||
|
/// Licenced under MIT
|
||||||
|
/// \brief definition of the main class of the application
|
||||||
|
|
||||||
|
// system includes
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
// own includes
|
||||||
|
#include "image.h"
|
||||||
|
|
||||||
|
Image::Image(uint16_t width, uint16_t height, uint8_t channels, uint8_t bits, void* pixels) {
|
||||||
|
m_width = width;
|
||||||
|
m_height = height;
|
||||||
|
m_channels = channels;
|
||||||
|
m_pixels = pixels;
|
||||||
|
m_ownPixel = false;
|
||||||
|
m_bitsPerChannel = bits;
|
||||||
|
}
|
||||||
|
|
||||||
|
Image::~Image() {
|
||||||
|
if (m_ownPixel && m_pixels) {
|
||||||
|
free(m_pixels);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bool Image::allocateMemory() {
|
||||||
|
if (m_ownPixel && m_pixels) {
|
||||||
|
free(m_pixels);
|
||||||
|
}
|
||||||
|
m_pixels = reinterpret_cast<uint8_t*>(malloc(m_width * m_height * m_channels * m_bitsPerChannel / 8));
|
||||||
|
bzero(m_pixels, m_width * m_height * m_channels * m_bitsPerChannel / 8);
|
||||||
|
if (m_pixels) {
|
||||||
|
m_ownPixel = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* Image::getPixels8() const {
|
||||||
|
return reinterpret_cast<uint8_t*>(m_pixels);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t* Image::getPixels16() const {
|
||||||
|
return reinterpret_cast<uint16_t*>(m_pixels);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t Image::getHeight() const {
|
||||||
|
return m_height;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t Image::getWidth() const {
|
||||||
|
return m_width;
|
||||||
|
}
|
|
@ -0,0 +1,52 @@
|
||||||
|
/// \file image.h
|
||||||
|
/// \copyright 2022 Sascha Nitsch
|
||||||
|
/// Licence under MIT license
|
||||||
|
/// \brief declaration of the Image class
|
||||||
|
|
||||||
|
#ifndef IMAGE_H_
|
||||||
|
#define IMAGE_H_
|
||||||
|
// system includes
|
||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
|
/// wrapper for pixel data of an image
|
||||||
|
class Image {
|
||||||
|
public:
|
||||||
|
/// constructor
|
||||||
|
/// \param width width in pixel
|
||||||
|
/// \param height height in pixel
|
||||||
|
/// \param channels number of channels
|
||||||
|
/// \param bits number of bits per channel
|
||||||
|
/// \param pixels optional memory for the image
|
||||||
|
Image(uint16_t width, uint16_t height, uint8_t channels, uint8_t bits, void* pixels = nullptr);
|
||||||
|
/// destructor
|
||||||
|
~Image();
|
||||||
|
/// \brief allocate memory for image data
|
||||||
|
bool allocateMemory();
|
||||||
|
/// \brief get pointer to pixel data
|
||||||
|
/// \return pointer to pixel data
|
||||||
|
uint8_t* getPixels8() const;
|
||||||
|
/// \brief get pointer to pixel data
|
||||||
|
/// \return pointer to pixel data
|
||||||
|
uint16_t* getPixels16() const;
|
||||||
|
/// \brief get width of image
|
||||||
|
/// \return width of image
|
||||||
|
uint16_t getWidth() const;
|
||||||
|
/// \brief get height of image
|
||||||
|
/// \return height of image
|
||||||
|
uint16_t getHeight() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
/// image width
|
||||||
|
uint16_t m_width;
|
||||||
|
/// image height
|
||||||
|
uint16_t m_height;
|
||||||
|
/// number of channels
|
||||||
|
uint8_t m_channels;
|
||||||
|
/// image data as RGB 8 or 16 bit per channel
|
||||||
|
void* m_pixels;
|
||||||
|
/// do we own the pixel memory?
|
||||||
|
bool m_ownPixel;
|
||||||
|
/// number of bits per channel
|
||||||
|
uint8_t m_bitsPerChannel;
|
||||||
|
};
|
||||||
|
#endif // IMAGE_H_
|
|
@ -0,0 +1,18 @@
|
||||||
|
/// \file init.cpp
|
||||||
|
/// \copyright 2022 Sascha Nitsch
|
||||||
|
/// Licencend under MIT license
|
||||||
|
/// \biref main entry point of the application
|
||||||
|
|
||||||
|
// own includes
|
||||||
|
#include "main.h"
|
||||||
|
|
||||||
|
/// \brief main entry point
|
||||||
|
/// \param argc number of argument
|
||||||
|
/// \param argv array of arguments
|
||||||
|
int main(int argc, const char* argv[]) {
|
||||||
|
Main main;
|
||||||
|
if (main.init(argc, argv) && main.run()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
|
@ -0,0 +1,79 @@
|
||||||
|
/// \file main.cpp
|
||||||
|
/// \copyright 2022 Sascha Nitsch
|
||||||
|
/// Licenced under MIT
|
||||||
|
/// \brief definition of the main class of the application
|
||||||
|
|
||||||
|
// system includes
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <OpenImageIO/imageio.h>
|
||||||
|
|
||||||
|
// own includes
|
||||||
|
#include "main.h"
|
||||||
|
// algorithms
|
||||||
|
#include "algorithm/distancepath.h"
|
||||||
|
|
||||||
|
Main::Main() {
|
||||||
|
m_algorithm = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
Main::~Main() {
|
||||||
|
delete m_algorithm;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Main::init(int argc, const char* argv[]) {
|
||||||
|
if (argc < 3) {
|
||||||
|
printUsage(argv[0]);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
m_inputFilename = argv[1];
|
||||||
|
m_outputFilename = argv[2];
|
||||||
|
const char* algorithmName = argv[3];
|
||||||
|
if (!strcmp(algorithmName, "distancepath")) {
|
||||||
|
m_algorithm = new Algorithm::DistancePath(argc - 4, &argv[4]);
|
||||||
|
}
|
||||||
|
if (m_algorithm) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
printf("algorithm \"%s\" not found\n", algorithmName);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Main::printUsage(const char* programName) {
|
||||||
|
printf("Usage: %s input.png output.png algorithm <algoritm arguments>\n", programName);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Main::run() {
|
||||||
|
if (!m_algorithm) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// load input image
|
||||||
|
auto inp = OIIO::ImageInput::open(m_inputFilename);
|
||||||
|
if (!inp) {
|
||||||
|
printf("Loading of input image \"%s\" failed %s\n", m_inputFilename.c_str(), OIIO::geterror().c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const OIIO::ImageSpec &spec = inp->spec();
|
||||||
|
Image input(spec.width, spec.height, spec.nchannels, 8);
|
||||||
|
input.allocateMemory();
|
||||||
|
inp->read_image(0, 0, 0, 3, OIIO::TypeDesc::UINT8, input.getPixels8());
|
||||||
|
inp->close();
|
||||||
|
// create output image
|
||||||
|
Image output(spec.width, spec.height, 3, 16);
|
||||||
|
output.allocateMemory();
|
||||||
|
int ret = m_algorithm->process(&input, &output);
|
||||||
|
if (ret == 0) {
|
||||||
|
OIIO::ImageSpec ospec;
|
||||||
|
ospec.width = spec.width;
|
||||||
|
ospec.height = spec.height;
|
||||||
|
ospec.nchannels = 3;
|
||||||
|
ospec.format = OIIO::TypeDesc::UINT16;
|
||||||
|
auto outp = OIIO::ImageOutput::create(m_outputFilename);
|
||||||
|
if (outp) {
|
||||||
|
outp->open(m_outputFilename, ospec);
|
||||||
|
outp->write_image(OIIO::TypeDesc::UINT16, output.getPixels16());
|
||||||
|
outp->close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret == 0;
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
/// \file main.h
|
||||||
|
/// \copyright 2022 Sascha Nitsch
|
||||||
|
/// Licence under MIT license
|
||||||
|
/// \brief declaration of the main class for the application
|
||||||
|
|
||||||
|
#ifndef MAIN_H_
|
||||||
|
#define MAIN_H_
|
||||||
|
|
||||||
|
// system includes
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <string>
|
||||||
|
// own includes
|
||||||
|
#include "algorithm/algorithm.h"
|
||||||
|
|
||||||
|
/// main class
|
||||||
|
class Main {
|
||||||
|
public:
|
||||||
|
/// \brief constructor
|
||||||
|
Main();
|
||||||
|
/// \brief destructor
|
||||||
|
~Main();
|
||||||
|
/// \brief initialize algorithm
|
||||||
|
/// \param argc number of arguments
|
||||||
|
/// \param argv list of arguments
|
||||||
|
/// \return true on success
|
||||||
|
bool init(int argc, const char* argv[]);
|
||||||
|
/// \brief run algorithm
|
||||||
|
/// \return true on success
|
||||||
|
bool run();
|
||||||
|
|
||||||
|
private:
|
||||||
|
/// \brief print program usage
|
||||||
|
/// \param programName name of our program
|
||||||
|
void printUsage(const char* programName);
|
||||||
|
/// input image filename
|
||||||
|
std::string m_inputFilename;
|
||||||
|
/// output image filename
|
||||||
|
std::string m_outputFilename;
|
||||||
|
/// pointer to the to be used algorithm
|
||||||
|
Algorithm::Algorithm* m_algorithm;
|
||||||
|
};
|
||||||
|
#endif // MAIN_H_
|
Loading…
Reference in New Issue