less duplicate code

This commit is contained in:
Phuntsok Drak-pa 2019-04-02 10:37:14 +02:00
parent 15488ace23
commit 72b91ab1b1
2 changed files with 91 additions and 45 deletions

View File

@ -4,6 +4,33 @@
#include <opencv2/core/core.hpp> #include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp> #include <opencv2/highgui/highgui.hpp>
#include <spdlog/spdlog.h> #include <spdlog/spdlog.h>
#include <tuple>
#include <vector>
namespace methods_private {
[[nodiscard]] auto randomColor();
[[nodiscard]] auto getColorSet(cv::Mat const& t_reference);
[[nodiscard]] auto getSquareValues(cv::Mat const& t_img);
[[nodiscard]] auto createCandidate(
cv::Mat const& t_base,
cv::Mat const& t_ref,
std::vector<std::array<uchar, 3>> const& t_colors,
double const diff,
bool const t_controlled_size);
void adjustSize(cv::Mat const& t_process_img,
cv::Point& t_top_left,
int t_size);
void threadedGetColor(cv::Mat const& t_reference,
std::vector<std::array<uchar, 3>>& t_colors,
int t_h);
void newSquare1(cv::Mat& t_process_img, cv::Point&& t_top_left, int t_size);
void newSquare2(cv::Mat& t_process_img,
cv::Point&& t_top_left,
int t_size,
std::array<uchar, 3> const& t_color);
} // namespace methods_private
void method1(cv::Mat const&, cv::Mat&, int); void method1(cv::Mat const&, cv::Mat&, int);

View File

@ -4,7 +4,9 @@
#include <algorithm> #include <algorithm>
#include <array> #include <array>
#include <cstdlib> #include <cstdlib>
#include <optional>
#include <thread> #include <thread>
#include <utility>
#include <vector> #include <vector>
auto const thread_nbr = std::thread::hardware_concurrency(); auto const thread_nbr = std::thread::hardware_concurrency();
@ -17,6 +19,57 @@ using std::rand;
namespace methods_private { namespace methods_private {
[[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);
}
[[nodiscard]] auto createCandidate(cv::Mat const& t_base,
cv::Mat const& t_ref,
ColorSet const& t_colors,
double const diff,
bool const t_controlled_size)
{
auto temp_image = t_base.clone();
auto const [rand_x, rand_y, size]
= methods_private::getSquareValues(temp_image);
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(
std::move(temp_image), new_diff)}
: std::nullopt;
}
void adjustSize(cv::Mat const& t_process_img, cv::Point& t_top_left, int size) 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 height = t_process_img.size().height;
@ -31,18 +84,6 @@ void adjustSize(cv::Mat const& t_process_img, cv::Point& t_top_left, int size)
} }
} }
[[nodiscard]] auto randomColor() -> cv::Scalar
{
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) void threadedGetColor(cv::Mat const& t_reference, ColorSet& t_colors, int t_h)
{ {
if (t_h > t_reference.size().height) if (t_h > t_reference.size().height)
@ -60,21 +101,10 @@ void threadedGetColor(cv::Mat const& t_reference, ColorSet& t_colors, int t_h)
} }
} }
[[nodiscard]] auto getColorSet(cv::Mat const& t_reference) -> ColorSet void newSquare1(cv::Mat& t_process_img, cv::Point&& t_top_left, int t_size)
{ {
ColorSet res{}; adjustSize(t_process_img, t_top_left, t_size);
for (int h = 0; h < t_reference.size().height; h += thread_nbr) { draw_shape(t_process_img, t_top_left, t_size, randomColor(), Shapes::Square);
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;
} }
void newSquare2(cv::Mat& t_process_img, void newSquare2(cv::Mat& t_process_img,
@ -97,11 +127,8 @@ void method1(cv::Mat const& t_reference, cv::Mat& t_output, int t_iterations)
spdlog::debug("Beginning method1, initial difference: {}", diff); spdlog::debug("Beginning method1, initial difference: {}", diff);
while (t_iterations > 0 && diff >= 0) { while (t_iterations > 0 && diff >= 0) {
auto temp_image = t_output.clone(); auto temp_image = t_output.clone();
int const rand_x = rand() % temp_image.size().width; auto const [rand_x, rand_y, size]
int const rand_y = rand() % temp_image.size().height; = methods_private::getSquareValues(temp_image);
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); methods_private::newSquare1(temp_image, cv::Point{rand_x, rand_y}, size);
if (auto const new_diff = euclidian_distance(t_reference, temp_image); if (auto const new_diff = euclidian_distance(t_reference, temp_image);
new_diff < diff) { new_diff < diff) {
@ -115,25 +142,17 @@ void method1(cv::Mat const& t_reference, cv::Mat& t_output, int t_iterations)
void method2(cv::Mat const& t_reference, cv::Mat& t_output, int t_iterations) void method2(cv::Mat const& t_reference, cv::Mat& t_output, int t_iterations)
{ {
spdlog::debug("Running on {} thread(s).", thread_nbr);
auto diff = euclidian_distance(t_reference, t_output); auto diff = euclidian_distance(t_reference, t_output);
spdlog::debug("Beginning method2, initial difference: {}", diff); spdlog::debug("Beginning method2, initial difference: {}", diff);
spdlog::debug("Running {} threads.", thread_nbr);
auto const colors = methods_private::getColorSet(t_reference); auto const colors = methods_private::getColorSet(t_reference);
spdlog::debug("{} colors detected.", colors.size()); spdlog::debug("{} colors detected.", colors.size());
while (t_iterations > 0) { while (t_iterations > 0) {
auto temp_image = t_output.clone(); if (auto result = methods_private::createCandidate(t_output, t_reference,
int const rand_x = rand() % temp_image.size().width; colors, diff, false);
int const rand_y = rand() % temp_image.size().height; result.has_value()) {
int const size = rand() diff = result->second;
% std::min(t_reference.size().width - rand_x, result->first.copyTo(t_output);
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; --t_iterations;
spdlog::debug("iteration:{} diff:{}", t_iterations, diff); spdlog::debug("iteration:{} diff:{}", t_iterations, diff);
} }