main
Brett 2025-04-04 22:22:22 -04:00
parent 339046cc36
commit 4bb2b2b3af
11 changed files with 189 additions and 63 deletions

View File

@ -80,7 +80,7 @@
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseAssociativeContains/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseEraseAlgorithm/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseFamiliarTemplateSyntaxForGenericLambdas/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTooWideScope/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTooWideScope/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTooWideScopeInitStatement/@EntryIndexedValue" value="HINT" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantNamespaceDefinition/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppNonInlineFunctionDefinitionInHeaderFile/@EntryIndexedValue" value="WARNING" type="string" />

View File

@ -0,0 +1,6 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="CppTooWideScope" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
</profile>
</component>

View File

@ -5,6 +5,9 @@
<mapping directory="$PROJECT_DIR$/cmake-build-debug/_deps/freetype-src" vcs="Git" />
<mapping directory="$PROJECT_DIR$/cmake-build-debug/_deps/freetype-src/subprojects/dlg" vcs="Git" />
<mapping directory="$PROJECT_DIR$/cmake-build-debug/_deps/imgui-src" vcs="Git" />
<mapping directory="$PROJECT_DIR$/cmake-build-release-examples/_deps/freetype-src" vcs="Git" />
<mapping directory="$PROJECT_DIR$/cmake-build-release-examples/_deps/freetype-src/subprojects/dlg" vcs="Git" />
<mapping directory="$PROJECT_DIR$/cmake-build-release-examples/_deps/imgui-src" vcs="Git" />
<mapping directory="$PROJECT_DIR$/cmake-build-release/_deps/freetype-src" vcs="Git" />
<mapping directory="$PROJECT_DIR$/cmake-build-release/_deps/freetype-src/subprojects/dlg" vcs="Git" />
<mapping directory="$PROJECT_DIR$/cmake-build-release/_deps/imgui-src" vcs="Git" />

View File

@ -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)

View File

@ -31,4 +31,8 @@ std::array<image_pixel_t, IMAGE_DIMENSIONS * IMAGE_DIMENSIONS * 3>& get_image(bl
void cleanup();
std::array<image_storage_t, 3>& get_reference_image();
std::array<image_pixel_t, IMAGE_DIMENSIONS * IMAGE_DIMENSIONS * 3> to_gl_image(const std::array<image_storage_t, 3>& image);
#endif //GP_SYSTEM_H

View File

@ -25,6 +25,7 @@
#include <blt/logging/logging.h>
#include <blt/std/types.h>
#include <mutex>
#include <blt/std/hashmap.h>
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

@ -1 +1 @@
Subproject commit 0eea2189e37a372f7a012a07120ee0aed2b1646a
Subproject commit 0dc083e095393beaf88d58f07b6f06c04439cdb8

View File

@ -21,9 +21,17 @@
#include <operations.h>
#include <random>
#include "opencv2/imgcodecs.hpp"
#include <stb_perlin.h>
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<gp_program*, 3> programs;
std::vector<std::array<image_pixel_t, IMAGE_DIMENSIONS * IMAGE_DIMENSIONS * 3>> images;
@ -33,6 +41,7 @@ template <size_t Channel>
void fitness_func(const tree_t& tree, fitness_t& fitness, const blt::size_t index)
{
auto image = tree.get_evaluation_ref<image_t>();
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<float>(x) / (static_cast<float>(IMAGE_DIMENSIONS) / 2)) - 1)) + (1 - std::abs(
(static_cast<float>(y) / (static_cast<float>(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<float>(IMAGE_SIZE_CHANNELS);
@ -57,7 +66,7 @@ template <typename T>
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<float>(blt::mem::type_cast<blt::u32>(av) | blt::mem::type_cast<blt::u32>(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<float>(blt::mem::type_cast<blt::u32>(av) & blt::mem::type_cast<blt::u32>(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<float>(blt::mem::type_cast<blt::u32>(av) ^ blt::mem::type_cast<blt::u32>(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<float>(~blt::mem::type_cast<blt::u32>(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<float>(i % IMAGE_DIMENSIONS) + ofx, static_cast<float>(i / IMAGE_DIMENSIONS) + ofy, ofz,
lacunarity + 2, gain + 0.5f, 1.0f, static_cast<int>(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<image_t>(), make_sub<image_t>(), make_mul<image_t>(), make_div<image_t>(), op_image_x, op_image_y, op_image_sin,
op_image_cos, op_image_log, make_add<float>(), make_sub<float>(), make_mul<float>(), make_prot_div<float>(),
op_sin, op_cos, op_exp, op_log, lit);
builder.build(op_image_ephemeral, make_add<image_t>(), make_sub<image_t>(), make_mul<image_t>(), make_div<image_t>(), 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<float>(), make_sub<float>(), make_mul<float>(), make_prot_div<float>(), 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<image_storage_t, 3>& get_reference_image()
{
return reference_image;
}
std::array<image_pixel_t, IMAGE_DIMENSIONS * IMAGE_DIMENSIONS * 3> to_gl_image(const std::array<image_storage_t, 3>& image)
{
std::array<image_pixel_t, IMAGE_DIMENSIONS * IMAGE_DIMENSIONS * 3> 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;
}

View File

@ -48,9 +48,28 @@ std::array<image_storage_t, 3> 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<float>::max();
float max = std::numeric_limits<float>::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;

View File

@ -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<float>(data.width) - padding_x * 2 - padding_x * (images_x - 1) - 256) / images_x;
const float img_height = (static_cast<float>(data.height) - padding_y * 2 - padding_y * (images_y - 1) - 32) / images_y;
const float x = 256 + static_cast<float>(i) * img_width + padding_x * static_cast<float>(i) + img_width;
const float y = static_cast<float>(data.height) - (16 + static_cast<float>(j) * img_height + padding_y * static_cast<float>(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<float>(data.width) - padding_x * 2 - padding_x * (images_x - 1) - 256) / images_x;
const float img_height = (static_cast<float>(data.height) - padding_y * 2 - padding_y * (images_y - 1) - 32) / images_y;
const float x = 256 + static_cast<float>(i) * img_width + padding_x * static_cast<float>(i) + img_width;
const float y = static_cast<float>(data.height) - (16 + static_cast<float>(j) * img_height + padding_y * static_cast<float>(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);
}

BIN
transparent_girl.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 235 KiB