Currently moving from Gitlab to Gitea at https://labs.phundrak.com. Some features may not work anymore on this Gitlab instance.

changed program options, individual tiles load

parent 67626b34
......@@ -13,24 +13,34 @@
class ImageManipulator {
public:
ImageManipulator() = delete;
ImageManipulator(const ImageManipulator& other) = delete;
ImageManipulator(ImageManipulator&& other) noexcept = delete;
ImageManipulator& operator=(const ImageManipulator& other) = delete;
ImageManipulator& operator=(ImageManipulator&& other) noexcept = delete;
ImageManipulator(const ImageManipulator& other);
ImageManipulator(ImageManipulator&& other) noexcept;
[[nodiscard]] auto operator=(const ImageManipulator& other)
-> ImageManipulator;
[[nodiscard]] auto operator=(ImageManipulator&& other) noexcept
-> ImageManipulator;
// Load image from input, and prepare for output
ImageManipulator(std::filesystem::path const t_input_path,
std::filesystem::path const t_output_path,
int const iterations);
// ImageManipulator(cv::Mat const& t_origin_image,
// int const iterations,
// int const t_x,
// int const t_y,
// int const t_width,
// int const t_height);
ImageManipulator(cv::Mat const& t_origin_image,
int const iterations,
int const t_x,
int const t_y,
int const t_width,
int const t_height);
void exec_method(int const t_nb_method, bool const t_controlled_size);
void exec_method(int const t_nb_method,
bool const t_controlled_size,
int const t_cols,
int const t_rows,
int const t_submethod);
void write_file() const;
[[nodiscard]] auto const& get_generated_image() const noexcept
{
return generated_image_;
}
//! Destructor
virtual ~ImageManipulator() noexcept = default;
......@@ -51,21 +61,27 @@ class ImageManipulator {
cv::Point const& t_top_left,
int const t_size,
cv::Scalar const& t_color) const;
void update_gen_image(cv::Mat const& t_img, double const t_diff);
void update_gen_image(cv::Mat const& t_img, double const t_diff);
void method1();
void method2();
void method3();
void method4(bool const t_controlled_size);
void method5(bool const t_controlled_size,
int cols,
int const rows,
int const submethod);
std::vector<std::array<uchar, 3>> colors_
= std::vector<std::array<uchar, 3>>{};
cv::Mat const reference_;
cv::Mat generated_image_;
std::mutex colors_mutex_ = std::mutex{};
std::string const output_path_;
cv::Mat generated_image_
= cv::Mat{reference_.size().height, reference_.size().width, CV_8UC3,
cv::Scalar(0, 0, 0)};
mutable std::mutex colors_mutex_ = std::mutex{};
std::string const output_path_{""};
double diff_ = 0.0;
int const total_iterations_ = 0;
int remaining_iter_ = 0;
int const width_;
int const height_;
int remaining_iter_ = total_iterations_;
int const width_ = reference_.size().width;
int const height_ = reference_.size().height;
};
#ifndef GENETIC_IMAGE_INCLUDE_GENIMG_PARSEARGS_HH_
#define GENETIC_IMAGE_INCLUDE_GENIMG_PARSEARGS_HH_
#pragma once
#include <filesystem>
#include <tuple>
......@@ -10,7 +9,6 @@
int,
int,
int,
int,
bool,
bool>;
#endif /* GENETIC_IMAGE_INCLUDE_GENIMG_PARSEARGS_HH_ */
......@@ -7,19 +7,16 @@
int main(int ac, char** av)
{
std::srand(std::time(nullptr));
auto [input_file, output_file, iterations, method, columns, rows,
controlled_size, verbose]
auto const [input_file, output_file, iterations, method, cols, rows,
submethod, controlled_size, verbose]
= parse_args(ac, av);
if (rows == 0) {
rows = columns;
}
spdlog::set_level(verbose ? spdlog::level::debug : spdlog::level::info);
spdlog::set_pattern("[thread %t] %+");
spdlog::set_pattern("[thread %t] %+");
spdlog::debug("Input file:\t{}", input_file.native());
spdlog::debug("Output file:\t{}", output_file.native());
spdlog::debug("Iterations:\t{}", iterations);
ImageManipulator image_process{input_file, output_file, iterations};
image_process.exec_method(method, controlled_size);
image_process.exec_method(method, controlled_size, cols, rows, submethod);
image_process.write_file();
}
......@@ -8,7 +8,6 @@
#include <optional>
#include <utility>
std::mutex colors_mutex;
auto const thread_nbr = std::thread::hardware_concurrency();
///////////////////////////////////////////////////////////////////////////////
......@@ -20,15 +19,9 @@ ImageManipulator::ImageManipulator(std::filesystem::path const t_input_path,
std::filesystem::path const t_output_path,
int const t_iterations)
: reference_{cv::imread(t_input_path.native(), cv::IMREAD_COLOR)},
generated_image_{cv::Mat{reference_.size().height,
reference_.size().width, CV_8UC3,
cv::Scalar(0, 0, 0)}},
output_path_{t_output_path.native()},
diff_{euclidian_distance(generated_image_)},
total_iterations_{t_iterations},
remaining_iter_{t_iterations},
width_{reference_.size().width},
height_{reference_.size().height}
total_iterations_{t_iterations}
{
if (!reference_.data) {
spdlog::critical("Could not open or find image!\n");
......@@ -39,9 +32,72 @@ ImageManipulator::ImageManipulator(std::filesystem::path const t_input_path,
spdlog::debug("Height:\t{}", reference_.size().height);
}
ImageManipulator::ImageManipulator(cv::Mat const& t_origin_image,
int const t_iterations,
int const t_x,
int const t_y,
int const t_width,
int const t_height)
: reference_{t_origin_image(
cv::Range{t_y, std::min(t_y + t_height, t_origin_image.rows)},
cv::Range{t_x, std::min(t_x + t_width, t_origin_image.cols)})},
diff_{euclidian_distance(generated_image_)},
total_iterations_{t_iterations}
{
if (!reference_.data) {
spdlog::critical("Could not open or find image!\n");
exit(-1);
}
spdlog::debug("Image loaded!");
spdlog::debug("Width:\t{}", reference_.size().width);
spdlog::debug("Height:\t{}", reference_.size().height);
}
ImageManipulator::ImageManipulator(const ImageManipulator& other)
: colors_{other.colors_},
reference_{other.reference_},
generated_image_{other.generated_image_},
output_path_{other.output_path_},
diff_{other.diff_},
total_iterations_{other.total_iterations_},
remaining_iter_{other.remaining_iter_},
width_{other.width_},
height_{other.height_}
{
}
ImageManipulator::ImageManipulator(ImageManipulator&& other) noexcept
: colors_{std::move(other.colors_)},
reference_{std::move(other.reference_)},
generated_image_{std::move(other.generated_image_)},
output_path_{std::move(other.output_path_)},
diff_{std::move(other.diff_)},
total_iterations_{other.total_iterations_},
remaining_iter_{other.remaining_iter_},
width_{other.width_},
height_{other.height_}
{
}
// operators //////////////////////////////////////////////////////////////////
[[nodiscard]] auto ImageManipulator::operator=(const ImageManipulator& other)
-> ImageManipulator
{
return ImageManipulator(other);
}
[[nodiscard]] auto ImageManipulator::operator=(
ImageManipulator&& other) noexcept -> ImageManipulator
{
return ImageManipulator{std::move(other)};
}
// public methods /////////////////////////////////////////////////////////////
void ImageManipulator::exec_method(int const t_nb_method,
bool const t_controlled_size = false)
bool const t_controlled_size = false,
int const cols = 1,
int const rows = 0,
int const submethod = 1)
{
switch (t_nb_method) {
case 1: {
......@@ -60,6 +116,10 @@ void ImageManipulator::exec_method(int const t_nb_method,
method4(t_controlled_size);
break;
}
case 5: {
method5(t_controlled_size, cols, rows, submethod);
break;
}
default:
spdlog::error("Requested method {} is not implemented.", t_nb_method);
std::exit(-1);
......@@ -138,10 +198,9 @@ void ImageManipulator::write_file() const
void ImageManipulator::get_color_set()
{
for (int h = 0; h < reference_.size().height;
h += std::thread::hardware_concurrency()) {
for (int h = 0; h < reference_.size().height; h += thread_nbr) {
std::vector<std::thread> thread_list{};
for (auto i = 0u; i < std::thread::hardware_concurrency(); ++i) {
for (auto i = 0u; i < thread_nbr; ++i) {
thread_list.push_back(
std::thread(&ImageManipulator::threaded_get_color, this, h + i));
}
......@@ -226,7 +285,7 @@ void ImageManipulator::method2()
spdlog::debug("Beginning method2, initial difference: {}", diff_);
spdlog::debug("nb_total_iter: {}, nb_remaining_iter: {}", total_iterations_,
remaining_iter_);
spdlog::debug("Running on {} threads", std::thread::hardware_concurrency());
spdlog::debug("Running on {} threads", thread_nbr);
get_color_set();
spdlog::debug("{} colors detected", colors_.size());
while (remaining_iter_ > 0 && diff_ > 0.0) {
......@@ -238,10 +297,10 @@ void ImageManipulator::method2()
void ImageManipulator::method3()
{
spdlog::debug("Beginning method2, initial difference: {}", diff_);
spdlog::debug("Beginning method3, initial difference: {}", diff_);
spdlog::debug("nb_total_iter: {}, nb_remaining_iter: {}", total_iterations_,
remaining_iter_);
spdlog::debug("Running on {} threads", std::thread::hardware_concurrency());
spdlog::debug("Running on {} threads", thread_nbr);
get_color_set();
spdlog::debug("{} colors detected", colors_.size());
while (remaining_iter_ > 0 && diff_ > 0.0) {
......@@ -254,35 +313,66 @@ void ImageManipulator::method3()
void ImageManipulator::method4(bool const t_controlled_size)
{
spdlog::debug("Beginning method2, initial difference: {}", diff_);
spdlog::debug("Beginning method4, initial difference: {}", diff_);
spdlog::debug("nb_total_iter: {}, nb_remaining_iter: {}", total_iterations_,
remaining_iter_);
spdlog::debug("Running on {} threads", std::thread::hardware_concurrency());
spdlog::debug("Running on {} threads", thread_nbr);
get_color_set();
spdlog::debug("{} colors detected", colors_.size());
while(remaining_iter_ > 0 && diff_ > 0.0)
{
while (remaining_iter_ > 0 && diff_ > 0.0) {
std::vector<std::future<std::optional<std::pair<cv::Mat, double>>>>
results{};
std::vector<std::pair<cv::Mat, double>> values{};
for (size_t i = 0; i < std::thread::hardware_concurrency(); ++i) {
for (size_t i = 0; i < thread_nbr; ++i) {
results.push_back(std::async(std::launch::async,
&ImageManipulator::create_candidate, this,
t_controlled_size));
}
for (auto& elem : results) {
if(auto res = elem.get(); res.has_value() && res->second < diff_) {
values.push_back(*res);
}
}
if(values.size() > 0) {
size_t best = 0;
for(size_t i = 0; i < values.size(); ++i) {
if(values[i].second < values[best].second) {
best = i;
}
}
update_gen_image(values[best].first, values[best].second);
}
for (auto& elem : results) {
if (auto res = elem.get(); res.has_value() && res->second < diff_) {
values.push_back(*res);
}
}
if (values.size() > 0) {
size_t best = 0;
for (size_t i = 0; i < values.size(); ++i) {
if (values[i].second < values[best].second) {
best = i;
}
}
update_gen_image(values[best].first, values[best].second);
}
}
}
void ImageManipulator::method5(bool const t_controlled_size,
int cols,
int const rows,
int const submethod)
{
spdlog::debug("Beginning method5, initial difference: {}", diff_);
spdlog::debug("nb_total_iter: {}, nb_remaining_iter: {}", total_iterations_,
remaining_iter_);
spdlog::debug("Running on {} threads", thread_nbr);
if (cols == 0) {
cols = rows;
}
std::vector<std::vector<ImageManipulator>> tiles{};
int const tile_width = reference_.cols / cols;
int const tile_height = reference_.rows / rows;
spdlog::debug("tile: width:{}\theight:{}", tile_width, tile_height);
spdlog::debug("image: width:{}\theight:{}", reference_.cols, reference_.rows);
for (int i = 0; i < rows; ++i) {
std::vector<ImageManipulator> tile_row{};
for (int j = 0; j < cols; ++j) {
tile_row.emplace_back(
reference_, total_iterations_, i * tile_height, j * tile_width,
(i != rows - 1) ? tile_height
: tile_height + reference_.cols % tile_height,
(j != cols - 1) ? tile_width
: tile_width + reference_.cols % tile_width);
}
tiles.push_back(tile_row);
}
spdlog::debug("{} tiles", tiles.size());
}
......@@ -22,7 +22,7 @@ void processFilenames(po::variables_map const& vm,
}
[[nodiscard]] auto parse_args(int t_ac, char** t_av)
-> std::tuple<path, path, int, int, int, int, bool, bool>
-> std::tuple<path, path, int, int, int, int, int, bool, bool>
{
po::options_description desc("Allowed options");
desc.add_options()
......@@ -32,13 +32,16 @@ void processFilenames(po::variables_map const& vm,
"Image output path (default: \"output_\" + input path)")
("iterations,n", po::value<int>(), "Number of iterations (default: 2000)")
("method,m", po::value<int>(), "Method number to be used (default: 1)")
("columns,c", po::value<int>(),
("cols,c", po::value<int>(),
"For method 5 only, number of columns the reference image should be "
"divided into. (default: 1)")
("rows,r", po::value<int>(),
"For method 5 only, number of rows the reference image should be "
"divided into. If the value is equal to 0, then it will be assumed "
"there will be as many rows as there are collumns. (default: 0)")
("rows,r", po::value<int>(),
"For method 5 only, number of rows the reference image should be "
"divided into. (default: 1)")
("submethod,S", po::value<int>(),
"Sub-method that will be used to generate the individual tiles from "
"method 5. (default: 1)")
("size,s", "Enables controlled size of the random shapes")
("verbose,v", "Enables verbosity");
po::variables_map vm;
......@@ -58,7 +61,9 @@ void processFilenames(po::variables_map const& vm,
input_path, output_path,
vm.count("iterations") ? vm["iterations"].as<int>() : DEFAULT_ITERATIONS,
vm.count("method") ? vm["method"].as<int>() : 1,
vm.count("column") ? vm["column"].as<int>() : 1,
vm.count("rows") ? vm["rows"].as<int>() : 0, vm.count("size"),
vm.count("cols") ? vm["cols"].as<int>() : 0,
vm.count("rows") ? vm["rows"].as<int>() : 1,
vm.count("submethod") ? vm["submethod"].as<int>() : 1,
vm.count("size"),
vm.count("verbose"));
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment