diff --git a/.idea/editor.xml b/.idea/editor.xml
index f0ef147..eac463f 100644
--- a/.idea/editor.xml
+++ b/.idea/editor.xml
@@ -80,7 +80,7 @@
-
+
diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
new file mode 100644
index 0000000..7b20765
--- /dev/null
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
index f1804a4..1903173 100644
--- a/.idea/vcs.xml
+++ b/.idea/vcs.xml
@@ -5,6 +5,9 @@
+
+
+
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 8f47cb5..bdd1ccb 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.25)
-project(image-gp-2 VERSION 0.0.8)
+project(image-gp-2 VERSION 0.0.9)
option(ENABLE_ADDRSAN "Enable the address sanitizer" OFF)
option(ENABLE_UBSAN "Enable the ub sanitizer" OFF)
diff --git a/include/gp_system.h b/include/gp_system.h
index 6150081..c9816b9 100644
--- a/include/gp_system.h
+++ b/include/gp_system.h
@@ -31,4 +31,8 @@ std::array& get_image(bl
void cleanup();
+std::array& get_reference_image();
+
+std::array to_gl_image(const std::array& image);
+
#endif //GP_SYSTEM_H
diff --git a/include/image_storage.h b/include/image_storage.h
index acba1b9..aeaedff 100644
--- a/include/image_storage.h
+++ b/include/image_storage.h
@@ -25,6 +25,7 @@
#include
#include
#include
+#include
using image_pixel_t = float;
constexpr blt::i32 IMAGE_DIMENSIONS = 256;
@@ -49,6 +50,8 @@ struct image_storage_t
{
return data[(y * IMAGE_DIMENSIONS + x) * IMAGE_CHANNELS];
}
+
+ void normalize();
};
inline std::atomic_uint64_t g_allocated_blocks = 0;
@@ -68,11 +71,10 @@ struct image_cleaner_t
};
inline image_cleaner_t g_image_list;
-inline std::atomic_uint64_t g_image_counter = 0;
struct image_t
{
- image_t(): id(++g_image_counter)
+ explicit image_t()
{
image_storage_t* front = nullptr;
{
@@ -88,14 +90,8 @@ struct image_t
else
data = new image_storage_t;
++g_allocated_blocks;
-
- BLT_TRACE("Allocated {}!", id);
}
- image_t(const image_t& other) = default;
-
- image_t& operator=(const image_t& other) = default;
-
void drop()
{
{
@@ -104,7 +100,6 @@ struct image_t
}
data = nullptr;
++g_deallocated_blocks;
- BLT_TRACE("Deallocated {}!", id);
}
[[nodiscard]] void* as_void_const() const
@@ -117,6 +112,11 @@ struct image_t
return data->data.data();
}
+ void normalize() const
+ {
+ data->normalize();
+ }
+
friend image_t operator+(const image_t& lhs, const image_t& rhs);
friend image_t operator-(const image_t& lhs, const image_t& rhs);
@@ -137,7 +137,6 @@ struct image_t
private:
image_storage_t* data;
- blt::size_t id;
};
#endif //IMAGE_STORAGE_H
diff --git a/lib/blt-gp b/lib/blt-gp
index 0eea218..0dc083e 160000
--- a/lib/blt-gp
+++ b/lib/blt-gp
@@ -1 +1 @@
-Subproject commit 0eea2189e37a372f7a012a07120ee0aed2b1646a
+Subproject commit 0dc083e095393beaf88d58f07b6f06c04439cdb8
diff --git a/src/gp_system.cpp b/src/gp_system.cpp
index 5667970..65fcdb7 100644
--- a/src/gp_system.cpp
+++ b/src/gp_system.cpp
@@ -21,9 +21,17 @@
#include
#include
#include "opencv2/imgcodecs.hpp"
+#include
using namespace blt::gp;
+float filter_nan(const float f)
+{
+ if (std::isnan(f) || std::isinf(f) || std::isinf(-f))
+ return 0.0f;
+ return f;
+}
+
std::array programs;
std::vector> images;
@@ -33,6 +41,7 @@ template
void fitness_func(const tree_t& tree, fitness_t& fitness, const blt::size_t index)
{
auto image = tree.get_evaluation_ref();
+ image->normalize();
// std::memcpy(images[index].data.data(), image->get_data().data.data(), IMAGE_SIZE_BYTES);
auto& data = image->get_data();
@@ -44,8 +53,8 @@ void fitness_func(const tree_t& tree, fitness_t& fitness, const blt::size_t inde
auto multiplier = (1 - std::abs((static_cast(x) / (static_cast(IMAGE_DIMENSIONS) / 2)) - 1)) + (1 - std::abs(
(static_cast(y) / (static_cast(IMAGE_DIMENSIONS) / 2)) - 1));
- const auto diff = data.get(x, y) - reference_image[Channel].get(x, y);
- fitness.raw_fitness += (diff * diff) * multiplier;
+ const auto diff = filter_nan(data.get(x, y)) - reference_image[Channel].get(x, y);
+ fitness.raw_fitness += diff * diff * multiplier;
}
}
fitness.raw_fitness /= static_cast(IMAGE_SIZE_CHANNELS);
@@ -57,7 +66,7 @@ template
void setup_operations(gp_program* program)
{
static operation_t op_image_x([]() {
- image_t ret;
+ image_t ret{};
for (blt::size_t x = 0; x < IMAGE_DIMENSIONS; ++x)
{
for (blt::size_t y = 0; y < IMAGE_DIMENSIONS; ++y)
@@ -66,7 +75,7 @@ void setup_operations(gp_program* program)
return ret;
});
static operation_t op_image_y([]() {
- image_t ret;
+ image_t ret{};
for (blt::size_t x = 0; x < IMAGE_DIMENSIONS; ++x)
{
for (blt::size_t y = 0; y < IMAGE_DIMENSIONS; ++y)
@@ -75,47 +84,97 @@ void setup_operations(gp_program* program)
return ret;
});
static auto op_image_ephemeral = operation_t([program]() {
- image_t ret;
+ image_t ret{};
const auto value = program->get_random().get_float();
for (auto& v : ret.get_data().data)
v = value;
return ret;
}).set_ephemeral();
- static operation_t op_image_blend([](const image_t& a, const image_t& b, const float f) {
+ static operation_t op_image_blend([](const image_t a, const image_t b, const float f) {
const auto blend = std::min(std::max(f, 0.0f), 1.0f);
const auto beta = 1.0f - blend;
- image_t ret;
- const cv::Mat src1{IMAGE_DIMENSIONS, IMAGE_DIMENSIONS, CV_32FC1, a.as_void()};
- const cv::Mat src2{IMAGE_DIMENSIONS, IMAGE_DIMENSIONS, CV_32FC1, b.as_void()};
- cv::Mat dst{IMAGE_DIMENSIONS, IMAGE_DIMENSIONS, CV_32FC1, ret.get_data().data.data()};
+ image_t ret{};
+ const cv::Mat src1{IMAGE_DIMENSIONS, IMAGE_DIMENSIONS, CV_32F, a.as_void_const()};
+ const cv::Mat src2{IMAGE_DIMENSIONS, IMAGE_DIMENSIONS, CV_32F, b.as_void_const()};
+ cv::Mat dst{IMAGE_DIMENSIONS, IMAGE_DIMENSIONS, CV_32F, ret.get_data().data.data()};
addWeighted(src1, blend, src2, beta, 0.0, dst);
return ret;
}, "blend_image");
- static operation_t op_image_sin([](const image_t& a) {
- image_t ret;
+ static operation_t op_image_sin([](const image_t a) {
+ image_t ret{};
for (const auto& [i, v] : blt::enumerate(std::as_const(a.get_data().data)))
- ret.get_data().data[i] = std::sin(v);
+ ret.get_data().data[i] = filter_nan(std::sin(v));
return ret;
}, "sin_image");
- static operation_t op_image_cos([](const image_t& a) {
- image_t ret;
+ static operation_t op_image_cos([](const image_t a) {
+ image_t ret{};
for (const auto& [i, v] : blt::enumerate(std::as_const(a.get_data().data)))
- ret.get_data().data[i] = std::cos(v);
+ ret.get_data().data[i] = filter_nan(std::cos(v));
return ret;
}, "cos_image");
- static operation_t op_image_log([](const image_t& a) {
- image_t ret;
+ static operation_t op_image_log([](const image_t a) {
+ image_t ret{};
for (const auto& [i, v] : blt::enumerate(std::as_const(a.get_data().data)))
{
if (blt::f_equal(v, 0))
ret.get_data().data[i] = 0;
else if (v < 0)
- ret.get_data().data[i] = -std::log(-v);
+ ret.get_data().data[i] = -filter_nan(std::log(-v));
else
- ret.get_data().data[i] = std::log(v);
+ ret.get_data().data[i] = filter_nan(std::log(v));
}
return ret;
- }, "sin_image");
+ }, "log_image");
+ static operation_t op_image_exp([](const image_t a) {
+ image_t ret{};
+ for (const auto& [i, v] : blt::enumerate(std::as_const(a.get_data().data)))
+ ret.get_data().data[i] = filter_nan(std::exp(v));
+ return ret;
+ }, "exp_image");
+ static operation_t op_image_or([](const image_t a, const image_t b) {
+ image_t ret{};
+ for (const auto& [i, av, bv] : blt::in_pairs(std::as_const(a.get_data().data), std::as_const(b.get_data().data)).enumerate().flatten())
+ ret.get_data().data[i] = blt::mem::type_cast(blt::mem::type_cast(av) | blt::mem::type_cast(bv));
+ return ret;
+ }, "bit_or_image");
+ static operation_t op_image_and([](const image_t a, const image_t b) {
+ image_t ret{};
+ for (const auto& [i, av, bv] : blt::in_pairs(std::as_const(a.get_data().data), std::as_const(b.get_data().data)).enumerate().flatten())
+ ret.get_data().data[i] = blt::mem::type_cast(blt::mem::type_cast(av) & blt::mem::type_cast(bv));
+ return ret;
+ }, "bit_and_image");
+ static operation_t op_image_xor([](const image_t a, const image_t b) {
+ image_t ret{};
+ for (const auto& [i, av, bv] : blt::in_pairs(std::as_const(a.get_data().data), std::as_const(b.get_data().data)).enumerate().flatten())
+ ret.get_data().data[i] = blt::mem::type_cast(blt::mem::type_cast(av) ^ blt::mem::type_cast(bv));
+ return ret;
+ }, "bit_xor_image");
+ static operation_t op_image_not([](const image_t a, const image_t b) {
+ image_t ret{};
+ for (const auto& [i, av, bv] : blt::in_pairs(std::as_const(a.get_data().data), std::as_const(b.get_data().data)).enumerate().flatten())
+ ret.get_data().data[i] = blt::mem::type_cast(~blt::mem::type_cast(av));
+ return ret;
+ }, "bit_not_image");
+ static operation_t op_image_gt([](const image_t a, const image_t b) {
+ image_t ret{};
+ for (const auto& [i, av, bv] : blt::in_pairs(std::as_const(a.get_data().data), std::as_const(b.get_data().data)).enumerate().flatten())
+ ret.get_data().data[i] = av > bv ? av : bv;
+ return ret;
+ }, "gt_image");
+ static operation_t op_image_lt([](const image_t a, const image_t b) {
+ image_t ret{};
+ for (const auto& [i, av, bv] : blt::in_pairs(std::as_const(a.get_data().data), std::as_const(b.get_data().data)).enumerate().flatten())
+ ret.get_data().data[i] = av < bv ? av : bv;
+ return ret;
+ }, "lt_image");
+ static operation_t op_image_perlin([](const float ofx, const float ofy, const float ofz, const float lacunarity, const float gain,
+ const float octaves) {
+ image_t ret{};
+ for (const auto& [i, out] : blt::enumerate(ret.get_data().data))
+ out = stb_perlin_ridge_noise3(static_cast(i % IMAGE_DIMENSIONS) + ofx, static_cast(i / IMAGE_DIMENSIONS) + ofy, ofz,
+ lacunarity + 2, gain + 0.5f, 1.0f, static_cast(octaves));
+ return ret;
+ }, "perlin_image");
static operation_t op_sin([](const float a) {
return std::sin(a);
}, "sin_float");
@@ -137,18 +196,20 @@ void setup_operations(gp_program* program)
}, "lit_float").set_ephemeral();
operator_builder builder{};
- builder.build(make_add(), make_sub(), make_mul(), make_div(), op_image_x, op_image_y, op_image_sin,
- op_image_cos, op_image_log, make_add(), make_sub(), make_mul(), make_prot_div(),
- op_sin, op_cos, op_exp, op_log, lit);
+ builder.build(op_image_ephemeral, make_add(), make_sub(), make_mul(), make_div(), op_image_x, op_image_y,
+ op_image_sin, op_image_gt, op_image_lt, op_image_cos, op_image_log, op_image_exp, op_image_or, op_image_and, op_image_xor,
+ op_image_not, op_image_perlin, make_add(), make_sub(), make_mul(), make_prot_div(), op_sin, op_cos,
+ op_exp, op_log, lit);
program->set_operations(builder.grab());
}
void setup_gp_system(const blt::size_t population_size)
{
prog_config_t config{};
- config.set_pop_size(1);
- config.set_elite_count(0);
+ config.set_pop_size(population_size);
+ config.set_elite_count(2);
config.set_thread_count(0);
+ config.set_reproduction_chance(0);
// config.set_crossover_chance(0);
// config.set_mutation_chance(0);
// config.set_reproduction_chance(0);
@@ -219,3 +280,23 @@ void cleanup()
for (const auto program : programs)
delete program;
}
+
+std::array& get_reference_image()
+{
+ return reference_image;
+}
+
+std::array to_gl_image(const std::array& image)
+{
+ std::array image_data{};
+ for (blt::size_t x = 0; x < IMAGE_DIMENSIONS; ++x)
+ {
+ for (blt::size_t y = 0; y < IMAGE_DIMENSIONS; ++y)
+ {
+ image_data[(x * IMAGE_DIMENSIONS + y) * 3 + 0] = image[0].get(x, y);
+ image_data[(x * IMAGE_DIMENSIONS + y) * 3 + 1] = image[1].get(x, y);
+ image_data[(x * IMAGE_DIMENSIONS + y) * 3 + 2] = image[2].get(x, y);
+ }
+ }
+ return image_data;
+}
diff --git a/src/image_storage.cpp b/src/image_storage.cpp
index e148ddc..627d088 100644
--- a/src/image_storage.cpp
+++ b/src/image_storage.cpp
@@ -48,9 +48,28 @@ std::array image_storage_t::from_file(const std::string& pat
return {storage_r, storage_g, storage_b};
}
+void image_storage_t::normalize()
+{
+ float min = std::numeric_limits::max();
+ float max = std::numeric_limits::min();
+
+ for (auto& pixel : data)
+ {
+ if (std::isnan(pixel) || std::isinf(pixel))
+ pixel = 0;
+ if (pixel > max)
+ max = pixel;
+ if (pixel < min)
+ min = pixel;
+ }
+
+ for (auto& pixel : data)
+ pixel = (pixel - min) / (max - min);
+}
+
image_t operator/(const image_t& lhs, const image_t& rhs)
{
- const image_t ret;
+ const image_t ret{};
for (auto [ref, l, r] : blt::zip(ret.data->data, lhs.data->data, rhs.data->data))
ref = blt::f_equal(r, 0) ? 0 : l / r;
return ret;
@@ -58,7 +77,7 @@ image_t operator/(const image_t& lhs, const image_t& rhs)
image_t operator*(const image_t& lhs, const image_t& rhs)
{
- const image_t ret;
+ const image_t ret{};
for (auto [ref, l, r] : blt::zip(ret.data->data, lhs.data->data, rhs.data->data))
ref = l * r;
return ret;
@@ -66,7 +85,7 @@ image_t operator*(const image_t& lhs, const image_t& rhs)
image_t operator-(const image_t& lhs, const image_t& rhs)
{
- const image_t ret;
+ const image_t ret{};
for (auto [ref, l, r] : blt::zip(ret.data->data, lhs.data->data, rhs.data->data))
ref = l - r;
return ret;
@@ -74,7 +93,7 @@ image_t operator-(const image_t& lhs, const image_t& rhs)
image_t operator+(const image_t& lhs, const image_t& rhs)
{
- const image_t ret;
+ const image_t ret{};
for (auto [ref, l, r] : blt::zip(ret.data->data, lhs.data->data, rhs.data->data))
ref = l + r;
return ret;
diff --git a/src/main.cpp b/src/main.cpp
index 14b2ad1..62e6820 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -49,6 +49,9 @@ void init(const blt::gfx::window_data&)
gl_images.push_back(texture);
resources.set(std::to_string(i), texture);
}
+ const auto texture = new texture_gl2D(IMAGE_DIMENSIONS, IMAGE_DIMENSIONS, GL_RGBA8);
+ texture->upload(to_gl_image(get_reference_image()).data(), IMAGE_DIMENSIONS, IMAGE_DIMENSIONS, GL_RGB, GL_FLOAT);
+ resources.set("reference", texture);
global_matrices.create_internals();
resources.load_resources();
renderer_2d.create();
@@ -58,6 +61,9 @@ void init(const blt::gfx::window_data&)
void update(const blt::gfx::window_data& data)
{
+ constexpr float side_bar_width = 250;
+ static float top_bar_height = 0;
+
global_matrices.update_perspectives(data.width, data.height, 90, 0.1, 2000);
camera.update();
@@ -75,11 +81,11 @@ void update(const blt::gfx::window_data& data)
// Create the tab bar
if (ImGui::BeginTabBar("MainTabs"))
{
+ top_bar_height = ImGui::GetFrameHeight();
// 1. Run GP tab
if (ImGui::BeginTabItem("Run GP"))
{
- // Left child - fixed width (250px)
- ImGui::BeginChild("ControlPanel", ImVec2(250, 0), true);
+ ImGui::BeginChild("ControlPanel", ImVec2(side_bar_width, 0), true);
{
ImGui::Text("Control Panel");
ImGui::Separator();
@@ -94,7 +100,24 @@ void update(const blt::gfx::window_data& data)
// Right child - take the remaining space
ImGui::SameLine();
// ImGui::BeginChild("MainContent", ImVec2(0, 0), false, ImGuiWindowFlags_NoBackground);
- {}
+ {
+ constexpr int images_x = 10;
+ constexpr int images_y = 6;
+ for (int i = 0; i < images_x; i++)
+ {
+ for (int j = 0; j < images_y; j++)
+ {
+ constexpr float padding_x = 32;
+ constexpr float padding_y = 32;
+ const float img_width = (static_cast(data.width) - padding_x * 2 - padding_x * (images_x - 1) - 256) / images_x;
+ const float img_height = (static_cast(data.height) - padding_y * 2 - padding_y * (images_y - 1) - 32) / images_y;
+ const float x = 256 + static_cast(i) * img_width + padding_x * static_cast(i) + img_width;
+ const float y = static_cast(data.height) - (16 + static_cast(j) * img_height + padding_y * static_cast(j) +
+ img_height);
+ renderer_2d.drawRectangle(blt::gfx::rectangle2d_t{x, y, img_width, img_height}, std::to_string(i * images_y + j));
+ }
+ }
+ }
// ImGui::EndChild();
ImGui::EndTabItem();
@@ -116,6 +139,14 @@ void update(const blt::gfx::window_data& data)
ImGui::EndTabItem();
}
+ if (ImGui::BeginTabItem("Reference"))
+ {
+ auto w = data.width;
+ auto h = data.height - top_bar_height - 10;
+ renderer_2d.drawRectangle({w/2, h/2, w, h}, "reference");
+ ImGui::EndTabItem();
+ }
+
ImGui::EndTabBar();
}
@@ -153,23 +184,6 @@ void update(const blt::gfx::window_data& data)
gl_images[i]->upload(get_image(i).data(), IMAGE_DIMENSIONS, IMAGE_DIMENSIONS, GL_RGB, GL_FLOAT);
}
- constexpr int images_x = 10;
- constexpr int images_y = 6;
- for (int i = 0; i < images_x; i++)
- {
- for (int j = 0; j < images_y; j++)
- {
- constexpr float padding_x = 32;
- constexpr float padding_y = 32;
- const float img_width = (static_cast(data.width) - padding_x * 2 - padding_x * (images_x - 1) - 256) / images_x;
- const float img_height = (static_cast(data.height) - padding_y * 2 - padding_y * (images_y - 1) - 32) / images_y;
- const float x = 256 + static_cast(i) * img_width + padding_x * static_cast(i) + img_width;
- const float y = static_cast(data.height) - (16 + static_cast(j) * img_height + padding_y * static_cast(j) +
- img_height);
- renderer_2d.drawRectangle(blt::gfx::rectangle2d_t{x, y, img_width, img_height}, std::to_string(i * images_y + j));
- }
- }
-
renderer_2d.render(data.width, data.height);
}
diff --git a/transparent_girl.png b/transparent_girl.png
new file mode 100644
index 0000000..1f3b52c
Binary files /dev/null and b/transparent_girl.png differ