2019-03-24 18:43:25 +00:00
|
|
|
#include "methods.hh"
|
2019-03-28 11:39:33 +00:00
|
|
|
#include "common.hh"
|
|
|
|
#include "drawing.hh"
|
2019-03-20 19:15:53 +00:00
|
|
|
#include <algorithm>
|
2019-03-21 01:49:00 +00:00
|
|
|
#include <array>
|
2019-03-25 11:24:19 +00:00
|
|
|
#include <cstdlib>
|
2019-04-08 00:48:25 +00:00
|
|
|
#include <future>
|
|
|
|
#include <iostream>
|
2019-04-02 08:37:14 +00:00
|
|
|
#include <optional>
|
2019-03-21 01:49:00 +00:00
|
|
|
#include <thread>
|
2019-04-02 08:37:14 +00:00
|
|
|
#include <utility>
|
2019-03-21 01:49:00 +00:00
|
|
|
#include <vector>
|
|
|
|
|
2019-03-25 16:14:57 +00:00
|
|
|
auto const thread_nbr = std::thread::hardware_concurrency();
|
2019-03-21 01:49:00 +00:00
|
|
|
std::mutex numbers_mutex;
|
2019-03-20 19:15:53 +00:00
|
|
|
|
|
|
|
using randint = std::uniform_int_distribution<>;
|
2019-03-21 01:49:00 +00:00
|
|
|
using Color = std::array<uchar, 3>;
|
|
|
|
using ColorSet = std::vector<Color>;
|
2019-03-25 11:24:19 +00:00
|
|
|
using std::rand;
|
2019-03-20 19:15:53 +00:00
|
|
|
|
2019-03-24 18:43:25 +00:00
|
|
|
namespace methods_private {
|
|
|
|
|
2019-04-02 08:37:14 +00:00
|
|
|
[[nodiscard]] auto randomColor()
|
|
|
|
{
|
|
|
|
static std::uniform_int_distribution<> dis(0, 255);
|
|
|
|
return cv::Scalar(rand() % 255, rand() % 255, rand() % 255);
|
|
|
|
}
|
|
|
|
|
|
|
|
[[nodiscard]] auto 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 (auto i = 0u; 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
[[nodiscard]] auto getSquareValues(cv::Mat const& t_img)
|
|
|
|
{
|
|
|
|
int rand_x = rand() % t_img.size().width;
|
|
|
|
int rand_y = rand() % t_img.size().height;
|
|
|
|
int size
|
|
|
|
= rand()
|
|
|
|
% std::min(t_img.size().width - rand_x, t_img.size().height - rand_y);
|
|
|
|
return std::tuple<int, int, int>(rand_x, rand_y, size);
|
|
|
|
}
|
|
|
|
|
2019-04-02 08:54:01 +00:00
|
|
|
[[nodiscard]] auto getControlledSquareValues(cv::Mat const& t_img,
|
|
|
|
int const t_init_iter,
|
|
|
|
int const t_iter)
|
|
|
|
{
|
|
|
|
int rand_x = rand() % t_img.size().width;
|
|
|
|
int rand_y = rand() % t_img.size().height;
|
|
|
|
float const coef
|
|
|
|
= static_cast<float>(t_iter) / static_cast<float>(t_init_iter);
|
|
|
|
int const min_size = static_cast<int>(
|
|
|
|
(static_cast<float>(std::min(t_img.size().width, t_img.size().height))
|
|
|
|
/ 2.0f)
|
|
|
|
* coef);
|
|
|
|
int const max_size = min_size * 2 + 1;
|
|
|
|
int size = rand() % (max_size - min_size) + min_size;
|
|
|
|
return std::tuple<int, int, int>(rand_x, rand_y, size);
|
|
|
|
}
|
|
|
|
|
2019-04-02 08:37:14 +00:00
|
|
|
[[nodiscard]] auto createCandidate(cv::Mat const& t_base,
|
|
|
|
cv::Mat const& t_ref,
|
|
|
|
ColorSet const& t_colors,
|
|
|
|
double const diff,
|
2019-04-02 08:54:01 +00:00
|
|
|
bool const t_controlled_size = false,
|
|
|
|
int const t_init_iter = 0,
|
|
|
|
int const t_iter = 0)
|
2019-04-02 08:37:14 +00:00
|
|
|
{
|
|
|
|
auto temp_image = t_base.clone();
|
|
|
|
auto const [rand_x, rand_y, size]
|
2019-04-07 22:57:54 +00:00
|
|
|
= t_controlled_size ? methods_private::getControlledSquareValues(
|
|
|
|
temp_image, t_init_iter, t_iter)
|
|
|
|
: methods_private::getSquareValues(temp_image);
|
2019-04-02 08:37:14 +00:00
|
|
|
methods_private::newSquare2(temp_image, cv::Point{rand_x, rand_y}, size,
|
|
|
|
t_colors[rand() % t_colors.size()]);
|
|
|
|
auto new_diff = euclidian_distance(t_ref, temp_image);
|
|
|
|
return (new_diff < diff)
|
|
|
|
? std::optional<std::pair<cv::Mat, double>>{std::make_pair(
|
2019-04-07 22:57:54 +00:00
|
|
|
std::move(temp_image), new_diff)}
|
2019-04-02 08:37:14 +00:00
|
|
|
: std::nullopt;
|
|
|
|
}
|
|
|
|
|
2019-03-28 11:26:05 +00:00
|
|
|
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;
|
|
|
|
}
|
2019-03-25 11:24:19 +00:00
|
|
|
}
|
|
|
|
|
2019-03-28 11:26:05 +00:00
|
|
|
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();
|
|
|
|
}
|
|
|
|
}
|
2019-03-21 01:49:00 +00:00
|
|
|
}
|
|
|
|
|
2019-04-02 08:37:14 +00:00
|
|
|
void newSquare1(cv::Mat& t_process_img, cv::Point&& t_top_left, int t_size)
|
2019-03-28 11:26:05 +00:00
|
|
|
{
|
2019-04-02 08:37:14 +00:00
|
|
|
adjustSize(t_process_img, t_top_left, t_size);
|
|
|
|
draw_shape(t_process_img, t_top_left, t_size, randomColor(), Shapes::Square);
|
2019-03-21 01:49:00 +00:00
|
|
|
}
|
|
|
|
|
2019-03-28 11:26:05 +00:00
|
|
|
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);
|
2019-03-21 01:49:00 +00:00
|
|
|
}
|
|
|
|
|
2019-03-28 11:26:05 +00:00
|
|
|
} // 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();
|
2019-04-02 08:37:14 +00:00
|
|
|
auto const [rand_x, rand_y, size]
|
|
|
|
= methods_private::getSquareValues(temp_image);
|
2019-03-28 11:26:05 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
2019-03-24 18:43:25 +00:00
|
|
|
}
|
|
|
|
|
2019-03-28 11:26:05 +00:00
|
|
|
void method2(cv::Mat const& t_reference, cv::Mat& t_output, int t_iterations)
|
|
|
|
{
|
2019-04-02 08:37:14 +00:00
|
|
|
spdlog::debug("Running on {} thread(s).", thread_nbr);
|
2019-03-28 11:26:05 +00:00
|
|
|
auto diff = euclidian_distance(t_reference, t_output);
|
|
|
|
spdlog::debug("Beginning method2, initial difference: {}", diff);
|
|
|
|
auto const colors = methods_private::getColorSet(t_reference);
|
|
|
|
spdlog::debug("{} colors detected.", colors.size());
|
|
|
|
while (t_iterations > 0) {
|
2019-04-02 08:54:01 +00:00
|
|
|
if (auto result
|
|
|
|
= methods_private::createCandidate(t_output, t_reference, colors, diff);
|
2019-04-02 08:37:14 +00:00
|
|
|
result.has_value()) {
|
|
|
|
diff = result->second;
|
|
|
|
result->first.copyTo(t_output);
|
2019-03-28 11:26:05 +00:00
|
|
|
--t_iterations;
|
|
|
|
spdlog::debug("iteration:{} diff:{}", t_iterations, diff);
|
|
|
|
}
|
|
|
|
}
|
2019-03-20 19:15:53 +00:00
|
|
|
}
|
2019-03-25 16:14:57 +00:00
|
|
|
|
2019-03-28 11:26:05 +00:00
|
|
|
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();
|
2019-04-02 08:54:01 +00:00
|
|
|
if (auto result = methods_private::createCandidate(
|
|
|
|
t_output, t_reference, colors, diff, true, init_iter, t_iterations);
|
|
|
|
result.has_value()) {
|
|
|
|
diff = result->second;
|
|
|
|
result->first.copyTo(t_output);
|
2019-03-28 11:26:05 +00:00
|
|
|
--t_iterations;
|
2019-04-02 08:54:01 +00:00
|
|
|
spdlog::debug("iteration:{} diff:{}", t_iterations, diff);
|
2019-03-28 11:26:05 +00:00
|
|
|
}
|
|
|
|
}
|
2019-03-25 16:14:57 +00:00
|
|
|
}
|
2019-04-08 00:48:25 +00:00
|
|
|
|
|
|
|
void method4(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) {
|
|
|
|
std::vector<std::future<std::optional<std::pair<cv::Mat, double>>>>
|
|
|
|
results{};
|
|
|
|
std::vector<std::pair<cv::Mat, double>> values{};
|
|
|
|
for (unsigned i = 0; i < thread_nbr; ++i) {
|
|
|
|
results.push_back(
|
|
|
|
std::async(std::launch::async, methods_private::createCandidate,
|
|
|
|
std::ref(t_output), std::ref(t_reference),
|
|
|
|
std::ref(colors), diff, true, init_iter, t_iterations));
|
|
|
|
}
|
|
|
|
for (auto& elem : results) {
|
|
|
|
if (auto res = elem.get(); res.has_value() && res->second < diff) {
|
|
|
|
values.push_back(*res);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(values.size() > 0) {
|
|
|
|
unsigned best = 0;
|
|
|
|
for(unsigned i = 0; i < values.size(); ++i) {
|
|
|
|
if(values[i].second < values[best].second) {
|
|
|
|
best = i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
diff = values[best].second;
|
|
|
|
values[best].first.copyTo(t_output);
|
|
|
|
--t_iterations;
|
|
|
|
spdlog::debug("iteration:{} diff:{}", t_iterations, diff);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|