genetic-images/src/methods.cc

165 lines
6.1 KiB
C++

#include "methods.hh"
#include "common.hh"
#include "drawing.hh"
#include <algorithm>
#include <array>
#include <cstdlib>
#include <thread>
#include <vector>
auto const thread_nbr = std::thread::hardware_concurrency();
std::mutex numbers_mutex;
using randint = std::uniform_int_distribution<>;
using Color = std::array<uchar, 3>;
using ColorSet = std::vector<Color>;
using std::rand;
namespace methods_private {
void adjustSize(cv::Mat const &t_process_img, cv::Point &t_top_left, int size) {
int const height = t_process_img.size().height;
int const width = t_process_img.size().width;
int const shape_total_width = t_top_left.x + size;
int const shape_total_height = t_top_left.y + size;
if (int const diff = shape_total_height - height; diff > 0) {
t_top_left.y -= diff + 1;
}
if (int const diff = shape_total_width - width; diff > 0) {
t_top_left.x -= diff + 1;
}
}
[[nodiscard]] cv::Scalar randomColor() {
static std::uniform_int_distribution<> dis(0, 255);
return cv::Scalar(rand() % 255, rand() % 255, rand() % 255);
}
void newSquare1(cv::Mat &t_process_img, cv::Point &&t_top_left, int t_size) {
adjustSize(t_process_img, t_top_left, t_size);
draw_shape(t_process_img, t_top_left, t_size, randomColor(), Shapes::Square);
}
void threadedGetColor(cv::Mat const &t_reference, ColorSet &t_colors, int t_h) {
if (t_h > t_reference.size().height)
return;
for (int w = 0; w < t_reference.size().width; w += 3) {
Color temp = {t_reference.at<uchar>(t_h, w),
t_reference.at<uchar>(t_h, w + 1),
t_reference.at<uchar>(t_h, w + 2)};
auto pos = std::find(std::begin(t_colors), std::end(t_colors), temp);
if (pos == std::end(t_colors)) {
numbers_mutex.lock();
t_colors.push_back(temp);
numbers_mutex.unlock();
}
}
}
[[nodiscard]] ColorSet getColorSet(cv::Mat const &t_reference) {
ColorSet res{};
for (int h = 0; h < t_reference.size().height; h += thread_nbr) {
std::vector<std::thread> thread_list{};
for (int i = 0; i < thread_nbr; ++i) {
thread_list.push_back(std::thread(methods_private::threadedGetColor,
std::ref(t_reference), std::ref(res),
h + i));
}
for (auto &th : thread_list)
th.join();
}
res.shrink_to_fit();
return res;
}
void newSquare2(cv::Mat &t_process_img, cv::Point &&t_top_left, int t_size,
Color const &t_color) {
draw_shape(t_process_img, t_top_left, t_size,
cv::Scalar{static_cast<double>(t_color[0]),
static_cast<double>(t_color[1]),
static_cast<double>(t_color[2])},
Shapes::Square);
}
} // namespace methods_private
void method1(cv::Mat const &t_reference, cv::Mat &t_output, int t_iterations) {
auto diff = euclidian_distance(t_reference, t_output);
spdlog::debug("Beginning method1, initial difference: {}", diff);
while (t_iterations > 0 && diff >= 0) {
auto temp_image = t_output.clone();
int const rand_x = rand() % temp_image.size().width;
int const rand_y = rand() % temp_image.size().height;
int const size = rand() % std::min(t_reference.size().width - rand_x,
t_reference.size().height - rand_y);
methods_private::newSquare1(temp_image, cv::Point{rand_x, rand_y}, size);
if (auto const new_diff = euclidian_distance(t_reference, temp_image);
new_diff < diff) {
diff = new_diff;
temp_image.copyTo(t_output);
--t_iterations;
spdlog::debug("iteration:{} diff:{}", t_iterations, diff);
}
}
}
void method2(cv::Mat const &t_reference, cv::Mat &t_output, int t_iterations) {
auto diff = euclidian_distance(t_reference, t_output);
spdlog::debug("Beginning method2, initial difference: {}", diff);
spdlog::debug("Running {} threads.", thread_nbr);
auto const colors = methods_private::getColorSet(t_reference);
spdlog::debug("{} colors detected.", colors.size());
while (t_iterations > 0) {
auto temp_image = t_output.clone();
int const rand_x = rand() % temp_image.size().width;
int const rand_y = rand() % temp_image.size().height;
int const size = rand() % std::min(t_reference.size().width - rand_x,
t_reference.size().height - rand_y);
methods_private::newSquare2(temp_image, cv::Point{rand_x, rand_y}, size,
colors[rand() % colors.size()]);
if (auto new_diff = euclidian_distance(t_reference, temp_image);
new_diff < diff) {
diff = new_diff;
temp_image.copyTo(t_output);
--t_iterations;
spdlog::debug("iteration:{} diff:{}", t_iterations, diff);
}
}
}
void method3(cv::Mat const &t_reference, cv::Mat &t_output, int t_iterations) {
auto const init_iter = t_iterations;
auto diff = euclidian_distance(t_reference, t_output);
spdlog::debug("Beginning method2, initial difference: {}", diff);
spdlog::debug("Running {} threads.", thread_nbr);
auto const colors = methods_private::getColorSet(t_reference);
spdlog::debug("{} colors detected.", colors.size());
while (t_iterations > 0) {
auto temp_image = t_output.clone();
int const rand_x = rand() % temp_image.size().width;
int const rand_y = rand() % temp_image.size().height;
float const coef =
static_cast<float>(t_iterations) / static_cast<float>(init_iter);
int const min_size = static_cast<int>(
(static_cast<float>(
std::min(t_reference.size().width, t_reference.size().height)) /
2.0f) *
coef);
int const max_size = min_size * 2 + 1;
int const size = rand() % (max_size - min_size) + min_size;
methods_private::newSquare2(temp_image, cv::Point{rand_x, rand_y}, size,
colors[rand() % colors.size()]);
if (auto new_diff = euclidian_distance(t_reference, temp_image);
new_diff < diff) {
diff = new_diff;
temp_image.copyTo(t_output);
spdlog::debug("iteration:{} diff:{} size: {} coef:{} min:{} max:{}",
t_iterations, diff, size, coef, min_size, max_size);
--t_iterations;
}
}
}