method 5 DONE
This commit is contained in:
parent
51bac1bdca
commit
8a34a40600
@ -1,29 +1,28 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <filesystem>
|
|
||||||
#include <opencv2/core/core.hpp>
|
|
||||||
#include <opencv2/highgui/highgui.hpp>
|
#include <opencv2/highgui/highgui.hpp>
|
||||||
#include <opencv2/imgproc.hpp>
|
#include <opencv2/imgproc.hpp>
|
||||||
#include <spdlog/spdlog.h>
|
#include <spdlog/spdlog.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <thread>
|
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
class ImageManipulator {
|
class ImageManipulator {
|
||||||
public:
|
public:
|
||||||
ImageManipulator() = delete;
|
ImageManipulator() = 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
|
/// \brief Copy contructor
|
||||||
ImageManipulator(std::filesystem::path const t_input_path,
|
ImageManipulator(const ImageManipulator& other);
|
||||||
std::filesystem::path const t_output_path,
|
|
||||||
|
/// \brief Move constructor
|
||||||
|
ImageManipulator(ImageManipulator&& other) noexcept;
|
||||||
|
|
||||||
|
/// \brief Load image from input, and prepare for output
|
||||||
|
ImageManipulator(std::string const t_input_path,
|
||||||
|
std::string const t_output_path,
|
||||||
int const iterations);
|
int const iterations);
|
||||||
|
|
||||||
|
/// \brief Basically makes views from image
|
||||||
ImageManipulator(cv::Mat const& t_origin_image,
|
ImageManipulator(cv::Mat const& t_origin_image,
|
||||||
int const iterations,
|
int const iterations,
|
||||||
int const t_x,
|
int const t_x,
|
||||||
@ -31,57 +30,96 @@ class ImageManipulator {
|
|||||||
int const t_width,
|
int const t_width,
|
||||||
int const t_height);
|
int const t_height);
|
||||||
|
|
||||||
|
/// \brief Copy assignment operator
|
||||||
|
[[nodiscard]] auto operator=(const ImageManipulator& other)
|
||||||
|
-> ImageManipulator;
|
||||||
|
|
||||||
|
/// \brief Move assignment operator
|
||||||
|
[[nodiscard]] auto operator=(ImageManipulator&& other) noexcept
|
||||||
|
-> ImageManipulator;
|
||||||
|
|
||||||
|
/// \brief Execute the nth method on the current object
|
||||||
void exec_method(int const t_nb_method,
|
void exec_method(int const t_nb_method,
|
||||||
bool const t_controlled_size,
|
bool const t_controlled_size,
|
||||||
int const t_cols,
|
int const t_cols,
|
||||||
int const t_rows,
|
int const t_rows,
|
||||||
int const t_submethod);
|
int const t_submethod);
|
||||||
|
|
||||||
|
/// \brief Write the generated image to the output path
|
||||||
void write_file() const;
|
void write_file() const;
|
||||||
|
|
||||||
|
/// \brief Returns a reference to the generated image
|
||||||
[[nodiscard]] auto const& get_generated_image() const noexcept
|
[[nodiscard]] auto const& get_generated_image() const noexcept
|
||||||
{
|
{
|
||||||
return generated_image_;
|
return generated_image_;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Destructor
|
/// \brief Destructor
|
||||||
virtual ~ImageManipulator() noexcept = default;
|
virtual ~ImageManipulator() noexcept = default;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
private:
|
private:
|
||||||
|
/// \brief Calculates the euclidian distance between two images
|
||||||
[[nodiscard]] auto euclidian_distance(cv::Mat const& t_img) const noexcept
|
[[nodiscard]] auto euclidian_distance(cv::Mat const& t_img) const noexcept
|
||||||
-> double;
|
-> double;
|
||||||
|
/// \brief Creates and returns a random color
|
||||||
[[nodiscard]] auto random_color() const noexcept;
|
[[nodiscard]] auto random_color() const noexcept;
|
||||||
|
/// \brief Generates random square coordinates
|
||||||
[[nodiscard]] auto get_square_values() const noexcept;
|
[[nodiscard]] auto get_square_values() const noexcept;
|
||||||
|
/// \brief Generates controlled random square coordinates
|
||||||
[[nodiscard]] auto get_controlled_square_values() const noexcept;
|
[[nodiscard]] auto get_controlled_square_values() const noexcept;
|
||||||
|
/// \brief Generates a candidate for image generation improvement
|
||||||
[[nodiscard]] auto create_candidate(bool const t_controlled_size) const;
|
[[nodiscard]] auto create_candidate(bool const t_controlled_size) const;
|
||||||
|
|
||||||
|
[[nodiscard]] auto generate_tiles(int const t_cols, int const t_rows) const;
|
||||||
|
|
||||||
|
/// \brief Gets all colors from the reference image
|
||||||
void get_color_set();
|
void get_color_set();
|
||||||
|
/// \brief Threaded helper for \ref get_color_set
|
||||||
void threaded_get_color(int t_h);
|
void threaded_get_color(int t_h);
|
||||||
void adjust_size(cv::Point& t_top_left, int const size) noexcept;
|
/// \brief Draw a square on an image
|
||||||
void draw_square(cv::Mat& t_img,
|
void draw_square(cv::Mat& t_img,
|
||||||
cv::Point const& t_top_left,
|
cv::Point const& t_top_left,
|
||||||
int const t_size,
|
int const t_size,
|
||||||
cv::Scalar const& t_color) const;
|
cv::Scalar const& t_color) const;
|
||||||
|
/// \brief Update this object’s generated image
|
||||||
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 merge_tiles(std::vector<std::vector<ImageManipulator>> t_tiles);
|
||||||
|
|
||||||
|
/// \brief First method as described in the
|
||||||
|
/// [report](https://labs.phundrak.fr/phundrak/genetic-images/blob/master/report/report.pdf)
|
||||||
void method1();
|
void method1();
|
||||||
|
/// \brief Second method as described in the
|
||||||
|
/// [report](https://labs.phundrak.fr/phundrak/genetic-images/blob/master/report/report.pdf)
|
||||||
void method2();
|
void method2();
|
||||||
|
/// \brief Third method as described in the
|
||||||
|
/// [report](https://labs.phundrak.fr/phundrak/genetic-images/blob/master/report/report.pdf)
|
||||||
void method3();
|
void method3();
|
||||||
|
/// \brief Fourth method as described in the
|
||||||
|
/// [report](https://labs.phundrak.fr/phundrak/genetic-images/blob/master/report/report.pdf)
|
||||||
void method4(bool const t_controlled_size);
|
void method4(bool const t_controlled_size);
|
||||||
|
/// \brief Fifth method as described in the
|
||||||
|
/// [report](https://labs.phundrak.fr/phundrak/genetic-images/blob/master/report/report.pdf)
|
||||||
void method5(bool const t_controlled_size,
|
void method5(bool const t_controlled_size,
|
||||||
int cols,
|
int const cols,
|
||||||
int const rows,
|
int const rows,
|
||||||
int const submethod);
|
int const submethod);
|
||||||
|
|
||||||
std::vector<std::array<uchar, 3>> colors_
|
std::vector<std::array<uchar, 3>> colors_
|
||||||
= std::vector<std::array<uchar, 3>>{};
|
= std::vector<std::array<uchar, 3>>{}; /*!< Color set from reference */
|
||||||
cv::Mat const reference_;
|
cv::Mat const reference_; /*!< Reference image */
|
||||||
cv::Mat generated_image_
|
cv::Mat generated_image_
|
||||||
= cv::Mat{reference_.size().height, reference_.size().width, CV_8UC3,
|
= cv::Mat{reference_.size().height, reference_.size().width, CV_8UC3,
|
||||||
cv::Scalar(0, 0, 0)};
|
cv::Scalar(0, 0, 0)}; /*!< Working, generated image */
|
||||||
mutable std::mutex colors_mutex_ = std::mutex{};
|
mutable std::mutex colors_mutex_
|
||||||
std::string const output_path_{""};
|
= std::mutex{}; /*!< Thread mutex for color set generation */
|
||||||
double diff_ = 0.0;
|
std::string const output_path_{""}; /*!< Write path for the generated image */
|
||||||
int const total_iterations_ = 0;
|
double diff_ = euclidian_distance(generated_image_); /*!< Euclidian difference
|
||||||
int remaining_iter_ = total_iterations_;
|
between \ref reference_ and \ref generated_image_ */
|
||||||
int const width_ = reference_.size().width;
|
int const total_iterations_ = 0; /*!< Number of iterations to perform */
|
||||||
int const height_ = reference_.size().height;
|
int remaining_iter_
|
||||||
|
= total_iterations_; /*!< Remaining iterations to perform */
|
||||||
|
int const width_ = reference_.size().width; /*!< Width of the image */
|
||||||
|
int const height_ = reference_.size().height; /*!< Height of the image */
|
||||||
};
|
};
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
|
|
||||||
|
/// \brief Parses the arguments passed to the program
|
||||||
[[nodiscard]] auto parse_args(int, char**) -> std::tuple<std::filesystem::path,
|
[[nodiscard]] auto parse_args(int, char**) -> std::tuple<std::filesystem::path,
|
||||||
std::filesystem::path,
|
std::filesystem::path,
|
||||||
int,
|
int,
|
||||||
|
328
src/methods.cc
328
src/methods.cc
@ -3,56 +3,21 @@
|
|||||||
#include <array>
|
#include <array>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
#include <functional>
|
||||||
#include <future>
|
#include <future>
|
||||||
#include <iostream>
|
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
#include <thread>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
auto const thread_nbr = std::thread::hardware_concurrency();
|
auto const thread_nbr = std::thread::hardware_concurrency();
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
// class implementation //
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// constructors ///////////////////////////////////////////////////////////////
|
// constructors ///////////////////////////////////////////////////////////////
|
||||||
ImageManipulator::ImageManipulator(std::filesystem::path const t_input_path,
|
/**
|
||||||
std::filesystem::path const t_output_path,
|
* Copy constructor of \ref ImageManipulator, will copy all of its members
|
||||||
int const t_iterations)
|
* except for its mutex.
|
||||||
: reference_{cv::imread(t_input_path.native(), cv::IMREAD_COLOR)},
|
*
|
||||||
output_path_{t_output_path.native()},
|
* \param[in] other Element to copy
|
||||||
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(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)
|
ImageManipulator::ImageManipulator(const ImageManipulator& other)
|
||||||
: colors_{other.colors_},
|
: colors_{other.colors_},
|
||||||
reference_{other.reference_},
|
reference_{other.reference_},
|
||||||
@ -66,6 +31,12 @@ ImageManipulator::ImageManipulator(const ImageManipulator& other)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Move constructor of \ref ImageManipulator, will move all of the input’s
|
||||||
|
* members except for its mutex, a new one will be made.
|
||||||
|
*
|
||||||
|
* \param[in] other Element to move
|
||||||
|
*/
|
||||||
ImageManipulator::ImageManipulator(ImageManipulator&& other) noexcept
|
ImageManipulator::ImageManipulator(ImageManipulator&& other) noexcept
|
||||||
: colors_{std::move(other.colors_)},
|
: colors_{std::move(other.colors_)},
|
||||||
reference_{std::move(other.reference_)},
|
reference_{std::move(other.reference_)},
|
||||||
@ -79,13 +50,78 @@ ImageManipulator::ImageManipulator(ImageManipulator&& other) noexcept
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an instance of \ref ImageManipulator based on an input path and an
|
||||||
|
* output path. It will load the input image from its first argument, and will
|
||||||
|
* write an output image when asked at the path passed as its second argument.
|
||||||
|
*
|
||||||
|
* \param[in] t_input_path Path for the input, reference image
|
||||||
|
* \param[in] t_output_path Path to the output image to write
|
||||||
|
*/
|
||||||
|
ImageManipulator::ImageManipulator(std::string const t_input_path,
|
||||||
|
std::string const t_output_path,
|
||||||
|
int const t_iterations)
|
||||||
|
: reference_{cv::imread(t_input_path, cv::IMREAD_COLOR)},
|
||||||
|
output_path_{t_output_path},
|
||||||
|
total_iterations_{t_iterations}
|
||||||
|
{
|
||||||
|
if (!reference_.data) {
|
||||||
|
spdlog::critical("Could not open or find image!\n");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a view of the input image, and will generate an image based only on
|
||||||
|
* that view.
|
||||||
|
*
|
||||||
|
* \param[in] t_origin_image Image to create a view from
|
||||||
|
* \param[in] t_iterations Number of iterations to perform on this view
|
||||||
|
* \param[in] t_x X value of the view’s origin (top left)
|
||||||
|
* \param[in] t_y Y value of the view’s origin (top left)
|
||||||
|
* \param[in] t_width Width of the view from its origin
|
||||||
|
* \param[in] t_height Height of the view from its origin
|
||||||
|
*/
|
||||||
|
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)})},
|
||||||
|
total_iterations_{t_iterations}
|
||||||
|
{
|
||||||
|
if (!reference_.data) {
|
||||||
|
spdlog::critical("Could not open or find image!\n");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// operators //////////////////////////////////////////////////////////////////
|
// operators //////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copy assignment operator, will copy all of the input’s members except for
|
||||||
|
* its mutex, a new one will be generated.
|
||||||
|
*
|
||||||
|
* \param[in] other Element to copy
|
||||||
|
* \return ImageManipulator
|
||||||
|
*/
|
||||||
[[nodiscard]] auto ImageManipulator::operator=(const ImageManipulator& other)
|
[[nodiscard]] auto ImageManipulator::operator=(const ImageManipulator& other)
|
||||||
-> ImageManipulator
|
-> ImageManipulator
|
||||||
{
|
{
|
||||||
return ImageManipulator(other);
|
return ImageManipulator(other);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Move assignment operator, will move all of the input’s members except for
|
||||||
|
* its mutex, a new one will be generated.
|
||||||
|
*
|
||||||
|
* \param[in] other Element to move
|
||||||
|
* \return ImageManipulator
|
||||||
|
*/
|
||||||
[[nodiscard]] auto ImageManipulator::operator=(
|
[[nodiscard]] auto ImageManipulator::operator=(
|
||||||
ImageManipulator&& other) noexcept -> ImageManipulator
|
ImageManipulator&& other) noexcept -> ImageManipulator
|
||||||
{
|
{
|
||||||
@ -93,11 +129,25 @@ ImageManipulator::ImageManipulator(ImageManipulator&& other) noexcept
|
|||||||
}
|
}
|
||||||
|
|
||||||
// public methods /////////////////////////////////////////////////////////////
|
// public methods /////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute one of the methods as described in the report. If a non-valid
|
||||||
|
* method is called, the program will be terminated. The argument
|
||||||
|
* `t_controlled_size` allows the program to have some control over the random
|
||||||
|
* size of the squares that will be generated. The arguments `t_cols`, `t_rows`
|
||||||
|
* and `submethod` are relevant to the fifth method.
|
||||||
|
*
|
||||||
|
* \param[in] t_nb_method Method identifier
|
||||||
|
* \param[in] t_controlled_size Control over the squares’ size
|
||||||
|
* \param[in] t_cols Number of columns the reference should be divided into
|
||||||
|
* \param[in] t_rows Number of rows the reference should be divided into
|
||||||
|
* \param[in] t_submethod
|
||||||
|
*/
|
||||||
void ImageManipulator::exec_method(int const t_nb_method,
|
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 t_cols = 1,
|
||||||
int const rows = 0,
|
int const t_rows = 0,
|
||||||
int const submethod = 1)
|
int const t_submethod = 1)
|
||||||
{
|
{
|
||||||
switch (t_nb_method) {
|
switch (t_nb_method) {
|
||||||
case 1: {
|
case 1: {
|
||||||
@ -117,7 +167,7 @@ void ImageManipulator::exec_method(int const t_nb_method,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 5: {
|
case 5: {
|
||||||
method5(t_controlled_size, cols, rows, submethod);
|
method5(t_controlled_size, t_cols, t_rows, t_submethod);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@ -126,6 +176,10 @@ void ImageManipulator::exec_method(int const t_nb_method,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write the generated image as a file to the specified path stored in the
|
||||||
|
* object
|
||||||
|
*/
|
||||||
void ImageManipulator::write_file() const
|
void ImageManipulator::write_file() const
|
||||||
{
|
{
|
||||||
cv::imwrite(output_path_, generated_image_);
|
cv::imwrite(output_path_, generated_image_);
|
||||||
@ -133,6 +187,13 @@ void ImageManipulator::write_file() const
|
|||||||
|
|
||||||
// private methods ////////////////////////////////////////////////////////////
|
// private methods ////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates the euclidian distance between the reference image and the image
|
||||||
|
* passed as an argument
|
||||||
|
*
|
||||||
|
* \param t_img Image with which the distance is computed
|
||||||
|
* \return double
|
||||||
|
*/
|
||||||
[[nodiscard]] auto ImageManipulator::euclidian_distance(
|
[[nodiscard]] auto ImageManipulator::euclidian_distance(
|
||||||
cv::Mat const& t_img) const noexcept -> double
|
cv::Mat const& t_img) const noexcept -> double
|
||||||
{
|
{
|
||||||
@ -145,11 +206,19 @@ void ImageManipulator::write_file() const
|
|||||||
return std::sqrt(euclidian);
|
return std::sqrt(euclidian);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \return cv::Scalar
|
||||||
|
*/
|
||||||
[[nodiscard]] auto ImageManipulator::random_color() const noexcept
|
[[nodiscard]] auto ImageManipulator::random_color() const noexcept
|
||||||
{
|
{
|
||||||
return cv::Scalar(rand() % 255, rand() % 255, rand() % 255);
|
return cv::Scalar(rand() % 255, rand() % 255, rand() % 255);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates random x/y coordinates for a square and the size of said square.
|
||||||
|
*
|
||||||
|
* \return Tuple of three ints
|
||||||
|
*/
|
||||||
[[nodiscard]] auto ImageManipulator::get_square_values() const noexcept
|
[[nodiscard]] auto ImageManipulator::get_square_values() const noexcept
|
||||||
{
|
{
|
||||||
int rand_x = rand() % reference_.size().width;
|
int rand_x = rand() % reference_.size().width;
|
||||||
@ -160,6 +229,13 @@ void ImageManipulator::write_file() const
|
|||||||
return std::tuple<int, int, int>(rand_x, rand_y, size);
|
return std::tuple<int, int, int>(rand_x, rand_y, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates random x/y coordinates for a square’s origin (top left), and a
|
||||||
|
* random size which’s max and minimal value are controled as mentionned in the
|
||||||
|
* [report](https://labs.phundrak.fr/phundrak/genetic-images/blob/master/report/report.pdf).
|
||||||
|
*
|
||||||
|
* \return Tuple of three ints
|
||||||
|
*/
|
||||||
[[nodiscard]] auto ImageManipulator::get_controlled_square_values() const
|
[[nodiscard]] auto ImageManipulator::get_controlled_square_values() const
|
||||||
noexcept
|
noexcept
|
||||||
{
|
{
|
||||||
@ -177,6 +253,15 @@ void ImageManipulator::write_file() const
|
|||||||
return std::tuple<int, int, int>(rand_x, rand_y, size);
|
return std::tuple<int, int, int>(rand_x, rand_y, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a temporary image on which a random square is drawn. If its
|
||||||
|
* euclidian distance with the reference image proves to be an improvement from
|
||||||
|
* the latest improvement before, then both the image and the distance are
|
||||||
|
* returned. Otherwise, nothing is returned.
|
||||||
|
*
|
||||||
|
* \param[in] t_controlled_size Enables controlled square size
|
||||||
|
* \return Optional pair of cv::Mat and double
|
||||||
|
*/
|
||||||
[[nodiscard]] auto ImageManipulator::create_candidate(
|
[[nodiscard]] auto ImageManipulator::create_candidate(
|
||||||
bool const t_controlled_size = false) const
|
bool const t_controlled_size = false) const
|
||||||
{
|
{
|
||||||
@ -196,6 +281,33 @@ void ImageManipulator::write_file() const
|
|||||||
: std::nullopt;
|
: std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] auto ImageManipulator::generate_tiles(int const t_cols,
|
||||||
|
int const t_rows) const
|
||||||
|
{
|
||||||
|
std::vector<std::vector<ImageManipulator>> tiles{};
|
||||||
|
int const tile_width = reference_.cols / t_cols;
|
||||||
|
int const tile_height = reference_.rows / t_rows;
|
||||||
|
for (int index_x = 0; index_x < t_cols; ++index_x) {
|
||||||
|
std::vector<ImageManipulator> tile_col{};
|
||||||
|
for (int index_y = 0; index_y < t_rows; ++index_y) {
|
||||||
|
int const width = (index_x != t_cols - 1)
|
||||||
|
? tile_width
|
||||||
|
: tile_width + reference_.cols % tile_width;
|
||||||
|
int const height = (index_y != t_rows - 1)
|
||||||
|
? tile_height
|
||||||
|
: tile_height + reference_.rows % tile_height;
|
||||||
|
tile_col.emplace_back(reference_, total_iterations_, index_x * tile_width,
|
||||||
|
index_y * tile_height, width, height);
|
||||||
|
}
|
||||||
|
tiles.push_back(tile_col);
|
||||||
|
}
|
||||||
|
return tiles;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Will analyse the reference image and will store each color found in member
|
||||||
|
* variable \ref colors_. Works on multithreading.
|
||||||
|
*/
|
||||||
void ImageManipulator::get_color_set()
|
void ImageManipulator::get_color_set()
|
||||||
{
|
{
|
||||||
for (int h = 0; h < reference_.size().height; h += thread_nbr) {
|
for (int h = 0; h < reference_.size().height; h += thread_nbr) {
|
||||||
@ -211,6 +323,12 @@ void ImageManipulator::get_color_set()
|
|||||||
colors_.shrink_to_fit();
|
colors_.shrink_to_fit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Will search for every color found in its designated column. If a new color
|
||||||
|
* is found, pauses all its other similar threads, adds the new color in \ref
|
||||||
|
* colors_, then resumes the other threads. Helper function for \ref
|
||||||
|
* get_color_set
|
||||||
|
*/
|
||||||
void ImageManipulator::threaded_get_color(int t_h)
|
void ImageManipulator::threaded_get_color(int t_h)
|
||||||
{
|
{
|
||||||
if (t_h > reference_.size().height) {
|
if (t_h > reference_.size().height) {
|
||||||
@ -229,19 +347,15 @@ void ImageManipulator::threaded_get_color(int t_h)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImageManipulator::adjust_size(cv::Point& t_top_left,
|
/**
|
||||||
int const size) noexcept
|
* Draw a square on the image passed as its argument, following its passed
|
||||||
{
|
* coordinates and with the passed color.
|
||||||
int const shape_total_width = t_top_left.x + size;
|
*
|
||||||
int const shape_total_height = t_top_left.y + size;
|
* \param[out] t_img Image to draw the square to
|
||||||
if (int const diff = shape_total_height + height_; diff > 0) {
|
* \param[in] t_top_left Origin of the square
|
||||||
t_top_left.x += diff + 1;
|
* \param[in] t_size Size of the square
|
||||||
}
|
* \param[in] t_color Color of the square
|
||||||
if (int const diff = shape_total_width + width_; diff > 0) {
|
*/
|
||||||
t_top_left.x += diff + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ImageManipulator::draw_square(cv::Mat& t_img,
|
void ImageManipulator::draw_square(cv::Mat& t_img,
|
||||||
cv::Point const& t_top_left,
|
cv::Point const& t_top_left,
|
||||||
int const t_size,
|
int const t_size,
|
||||||
@ -255,6 +369,16 @@ void ImageManipulator::draw_square(cv::Mat& t_img,
|
|||||||
fillConvexPoly(t_img, points.get(), 4, t_color);
|
fillConvexPoly(t_img, points.get(), 4, t_color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the object’s current generated image and difference with its
|
||||||
|
* reference by replacing them with the arguments passed in this function. This
|
||||||
|
* function should only be called if the passed elements are improving the
|
||||||
|
* generated image and reduce the euclidian distance between said image and its
|
||||||
|
* reference.
|
||||||
|
*
|
||||||
|
* \param[in] t_img Image to replace \ref generated_image_
|
||||||
|
* \param[in] t_diff New euclidian distance
|
||||||
|
*/
|
||||||
void ImageManipulator::update_gen_image(cv::Mat const& t_img,
|
void ImageManipulator::update_gen_image(cv::Mat const& t_img,
|
||||||
double const t_diff)
|
double const t_diff)
|
||||||
{
|
{
|
||||||
@ -264,6 +388,22 @@ void ImageManipulator::update_gen_image(cv::Mat const& t_img,
|
|||||||
spdlog::debug("remaining iter: {}\tdiff: {}", remaining_iter_, diff_);
|
spdlog::debug("remaining iter: {}\tdiff: {}", remaining_iter_, diff_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ImageManipulator::merge_tiles(
|
||||||
|
std::vector<std::vector<ImageManipulator>> t_tiles)
|
||||||
|
{
|
||||||
|
std::vector<cv::Mat> columns{};
|
||||||
|
for (auto const& col : t_tiles) {
|
||||||
|
std::vector<cv::Mat> column_arr{};
|
||||||
|
cv::Mat column_img{};
|
||||||
|
for (auto const& tile : col) {
|
||||||
|
column_arr.push_back(tile.get_generated_image());
|
||||||
|
}
|
||||||
|
vconcat(column_arr, column_img);
|
||||||
|
columns.push_back(std::move(column_img));
|
||||||
|
}
|
||||||
|
hconcat(columns, generated_image_);
|
||||||
|
}
|
||||||
|
|
||||||
void ImageManipulator::method1()
|
void ImageManipulator::method1()
|
||||||
{
|
{
|
||||||
spdlog::debug("Beginning method1, initial difference: {}", diff_);
|
spdlog::debug("Beginning method1, initial difference: {}", diff_);
|
||||||
@ -311,6 +451,9 @@ void ImageManipulator::method3()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \param[in] t_controlled_size Enables control over the random squares’ size
|
||||||
|
*/
|
||||||
void ImageManipulator::method4(bool const t_controlled_size)
|
void ImageManipulator::method4(bool const t_controlled_size)
|
||||||
{
|
{
|
||||||
spdlog::debug("Beginning method4, initial difference: {}", diff_);
|
spdlog::debug("Beginning method4, initial difference: {}", diff_);
|
||||||
@ -334,45 +477,50 @@ void ImageManipulator::method4(bool const t_controlled_size)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (values.size() > 0) {
|
if (values.size() > 0) {
|
||||||
size_t best = 0;
|
auto const pos
|
||||||
for (size_t i = 0; i < values.size(); ++i) {
|
= std::min_element(std::begin(values), std::end(values),
|
||||||
if (values[i].second < values[best].second) {
|
[](const auto& elem1, const auto& elem2) {
|
||||||
best = i;
|
return elem1.second < elem2.second;
|
||||||
}
|
});
|
||||||
}
|
update_gen_image(pos->first, pos->second);
|
||||||
update_gen_image(values[best].first, values[best].second);
|
// 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \param[in] t_controlled_size Enables control over the random squares’ size
|
||||||
|
* \param[in] t_cols Number of colomns the reference should be divided into
|
||||||
|
* \param[in] t_rows Number of rows the reference should be divided into
|
||||||
|
* \param[in] t_submethod Method to be used on each tile
|
||||||
|
*/
|
||||||
void ImageManipulator::method5(bool const t_controlled_size,
|
void ImageManipulator::method5(bool const t_controlled_size,
|
||||||
int cols,
|
int const t_cols,
|
||||||
int const rows,
|
int const t_rows,
|
||||||
int const submethod)
|
int const t_submethod)
|
||||||
{
|
{
|
||||||
spdlog::debug("Beginning method5, initial difference: {}", diff_);
|
spdlog::debug("Beginning method5, initial difference: {}", diff_);
|
||||||
spdlog::debug("nb_total_iter: {}, nb_remaining_iter: {}", total_iterations_,
|
spdlog::debug("nb_total_iter: {}, nb_remaining_iter: {}", total_iterations_,
|
||||||
remaining_iter_);
|
remaining_iter_);
|
||||||
spdlog::debug("Running on {} threads", thread_nbr);
|
spdlog::debug("Running on {} threads", thread_nbr);
|
||||||
if (cols == 0) {
|
auto tiles = generate_tiles((t_cols != 0) ? t_cols : t_rows, t_rows);
|
||||||
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());
|
spdlog::debug("{} tiles", tiles.size());
|
||||||
|
|
||||||
|
std::vector<std::thread> thread_list{};
|
||||||
|
for (auto& row : tiles) {
|
||||||
|
for (auto& tile : row) {
|
||||||
|
thread_list.emplace_back(
|
||||||
|
[&]() { tile.exec_method(t_submethod, t_controlled_size); });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (auto& th : thread_list) {
|
||||||
|
th.join();
|
||||||
|
}
|
||||||
|
merge_tiles(tiles);
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
#include "parseargs.hh"
|
#include "parseargs.hh"
|
||||||
#include <boost/program_options.hpp>
|
#include <boost/program_options.hpp>
|
||||||
#include <cstdlib>
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
constexpr int DEFAULT_ITERATIONS = 2000;
|
constexpr int DEFAULT_ITERATIONS = 2000;
|
||||||
@ -8,11 +7,23 @@ constexpr int DEFAULT_ITERATIONS = 2000;
|
|||||||
using path = std::filesystem::path;
|
using path = std::filesystem::path;
|
||||||
namespace po = boost::program_options;
|
namespace po = boost::program_options;
|
||||||
|
|
||||||
void processFilenames(po::variables_map const& vm,
|
/**
|
||||||
|
* \brief Ensures correct output path
|
||||||
|
*
|
||||||
|
* Checks if an output file exists, and if yes if it has an extension. In case
|
||||||
|
* it doesn’t exist, `output_` is appended at the beginning of the input
|
||||||
|
* filename. If the output path does not have an extension, the type `.png` is
|
||||||
|
* appended at the end of the path.
|
||||||
|
*
|
||||||
|
* \param[in] t_vm Arguments passed to the program
|
||||||
|
* \param[out] t_input Input path
|
||||||
|
* \param[out] t_output Output path
|
||||||
|
*/
|
||||||
|
void processFilenames(po::variables_map const& t_vm,
|
||||||
path const& t_input,
|
path const& t_input,
|
||||||
path& t_output)
|
path& t_output)
|
||||||
{
|
{
|
||||||
if (!vm.count("output")) {
|
if (!t_vm.count("output")) {
|
||||||
t_output.replace_filename("output_"
|
t_output.replace_filename("output_"
|
||||||
+ std::string{t_input.filename().string()});
|
+ std::string{t_input.filename().string()});
|
||||||
}
|
}
|
||||||
@ -21,6 +32,16 @@ void processFilenames(po::variables_map const& vm,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses the arguments given to the program, formats them and returns them as
|
||||||
|
* a tuple. If `-h` or `--help` or a malformed argument is passed, then the
|
||||||
|
* list of arguments and their comment will be displayed, and the program will
|
||||||
|
* exit.
|
||||||
|
*
|
||||||
|
* \param[in] t_ac Number of arguments passed to the program
|
||||||
|
* \param[in] t_av Arguments passed to the program
|
||||||
|
* \return Tuple of path, path, int, int, int, int, int, bool and bool
|
||||||
|
*/
|
||||||
[[nodiscard]] auto parse_args(int t_ac, char** t_av)
|
[[nodiscard]] auto parse_args(int t_ac, char** t_av)
|
||||||
-> std::tuple<path, path, int, int, int, int, int, bool, bool>
|
-> std::tuple<path, path, int, int, int, int, int, bool, bool>
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user