diff --git a/.gitmodules b/.gitmodules index 7e7534d..4bcab5b 100644 --- a/.gitmodules +++ b/.gitmodules @@ -10,3 +10,6 @@ [submodule "lib/stb"] path = lib/stb url = https://github.com/nothings/stb +[submodule "lib/blt-graphics"] + path = lib/blt-graphics + url = https://git.tpgc.me/tri11paragon/BLT-With-Graphics-Template.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 3512621..cdaf849 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.25) -project(image-gp-6 VERSION 0.0.4) +project(image-gp-6 VERSION 0.0.5) include(FetchContent) @@ -10,6 +10,7 @@ option(ENABLE_TSAN "Enable the thread data race sanitizer" OFF) set(CMAKE_CXX_STANDARD 17) add_subdirectory(lib/blt-gp) +add_subdirectory(lib/blt-graphics) find_package( OpenCV REQUIRED ) @@ -25,7 +26,7 @@ add_executable(image-gp-6 ${PROJECT_BUILD_FILES}) target_compile_options(image-gp-6 PRIVATE -Wall -Wextra -Wpedantic -Wno-comment) target_link_options(image-gp-6 PRIVATE -Wall -Wextra -Wpedantic -Wno-comment) -target_link_libraries(image-gp-6 PRIVATE BLT blt-gp ${OpenCV_LIBS}) +target_link_libraries(image-gp-6 PRIVATE BLT BLT_WITH_GRAPHICS blt-gp ${OpenCV_LIBS}) if (${ENABLE_ADDRSAN} MATCHES ON) target_compile_options(image-gp-6 PRIVATE -fsanitize=address) diff --git a/lib/blt-graphics b/lib/blt-graphics new file mode 160000 index 0000000..1470d84 --- /dev/null +++ b/lib/blt-graphics @@ -0,0 +1 @@ +Subproject commit 1470d8469d583f4a1b5aaf8916abbd4be2bba1ed diff --git a/lib/stb b/lib/stb index 013ac3b..f7f20f3 160000 --- a/lib/stb +++ b/lib/stb @@ -1 +1 @@ -Subproject commit 013ac3beddff3dbffafd5177e7972067cd2b5083 +Subproject commit f7f20f39fe4f206c6f19e26ebfef7b261ee59ee4 diff --git a/src/main.cpp b/src/main.cpp index 3303cde..75ede51 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -15,11 +15,6 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -#define STB_IMAGE_RESIZE_IMPLEMENTATION -#define STB_IMAGE_IMPLEMENTATION -#define STB_IMAGE_WRITE_IMPLEMENTATION -#define STB_PERLIN_IMPLEMENTATION - #include #include #include @@ -29,8 +24,12 @@ #include #include #include +#include +#include "blt/gfx/renderer/resource_manager.h" +#include "blt/gfx/renderer/batch_2d_renderer.h" +#include "blt/gfx/renderer/camera.h" +#include #include "opencv2/imgcodecs.hpp" -#include "opencv2/highgui.hpp" #include "opencv2/imgproc.hpp" #include @@ -39,6 +38,11 @@ static constexpr long IMAGE_SIZE = 128; static constexpr blt::size_t CHANNELS = 3; static constexpr blt::size_t DATA_SIZE = IMAGE_SIZE * IMAGE_SIZE; +blt::gfx::matrix_state_manager global_matrices; +blt::gfx::resource_manager resources; +blt::gfx::batch_renderer_2d renderer_2d(resources, global_matrices); +blt::gfx::first_person_camera_2d camera; + struct context { float x, y; @@ -46,50 +50,55 @@ struct context struct image_t { - std::array image_data; + std::array gray_data; }; struct full_image_t { - std::array image_data; + std::array rgb_data; void load(const std::string& path) { int width, height, channels; auto data = stbi_load(path.c_str(), &width, &height, &channels, CHANNELS); - stbir_resize_uint8_linear(data, width, height, 0, image_data.data(), IMAGE_SIZE, IMAGE_SIZE, 0, static_cast(CHANNELS)); + stbir_resize_uint8_linear(data, width, height, 0, rgb_data.data(), IMAGE_SIZE, IMAGE_SIZE, 0, static_cast(CHANNELS)); stbi_image_free(data); } void save(const std::string& str) { - stbi_write_png(str.c_str(), IMAGE_SIZE, IMAGE_SIZE, CHANNELS, image_data.data(), 0); + stbi_write_png(str.c_str(), IMAGE_SIZE, IMAGE_SIZE, CHANNELS, rgb_data.data(), 0); } }; -using fitness_data_t = std::array; +// +//using fitness_data_t = std::array; +// +//fitness_data_t fitness_red; +//fitness_data_t fitness_green; +//fitness_data_t fitness_blue; +std::array fitness_values; +std::array generation_images; +std::vector gl_images; -fitness_data_t fitness_red; -fitness_data_t fitness_green; -fitness_data_t fitness_blue; full_image_t base_data; full_image_t found_data; cv::Mat base_image_hsv; int h_bins = 50, s_bins = 60; -int histSize[] = { h_bins, s_bins }; +int histSize[] = {h_bins, s_bins}; // hue varies from 0 to 179, saturation from 0 to 255 -float h_ranges[] = { 0, 180 }; -float s_ranges[] = { 0, 256 }; +float h_ranges[] = {0, 180}; +float s_ranges[] = {0, 256}; -const float* ranges[] = { h_ranges, s_ranges }; +const float* ranges[] = {h_ranges, s_ranges}; // Use the 0-th and 1-st channels -int channels[] = { 0, 1, 2 }; +int channels[] = {0, 1, 2}; cv::Mat base_image_hist; @@ -100,7 +109,7 @@ blt::gp::prog_config_t config = blt::gp::prog_config_t() .set_max_generations(50) .set_mutation_chance(0.4) .set_crossover_chance(0.9) - .set_pop_size(50) + .set_pop_size(64) .set_thread_count(0); blt::gp::type_provider type_system; @@ -230,63 +239,74 @@ inline context get_ctx(blt::size_t i) return ctx; } -constexpr auto create_fitness_function(fitness_data_t& fitness_data, blt::size_t channel) +constexpr auto create_fitness_function(blt::size_t channel) { - return [&fitness_data, channel](blt::gp::tree_t& current_tree, blt::gp::fitness_t& fitness, blt::size_t in) { - auto& v = fitness_data[in]; + return [channel](blt::gp::tree_t& current_tree, blt::gp::fitness_t& fitness, blt::size_t in) { + auto& v = generation_images[in]; for (blt::size_t i = 0; i < DATA_SIZE; i++) { context ctx = get_ctx(i); - v.image_data[i] = static_cast(current_tree.get_evaluation_value(&ctx) * 255); - - auto dist = static_cast(v.image_data[i]) - static_cast(base_data.image_data[i * CHANNELS + channel]); - - fitness.raw_fitness += std::sqrt(dist * dist); + v.rgb_data[i * CHANNELS + channel] = static_cast(current_tree.get_evaluation_value(&ctx) * 255); } - BLT_TRACE("Hello1"); - cv::Mat img(IMAGE_SIZE, IMAGE_SIZE, CV_8UC3, v.image_data.data()); - BLT_TRACE("Hello2"); - cv::Mat img_hsv; - BLT_TRACE("Hello3"); - cv::cvtColor(img, img_hsv, cv::COLOR_RGB2HSV); - BLT_TRACE("Hello4"); - cv::Mat hist; - BLT_TRACE("Hello5"); - cv::calcHist(&img_hsv, 1, channels, cv::Mat(), hist, 2, histSize, ranges, true, false); - BLT_TRACE("Hello6"); - cv::normalize(hist, hist, 0, 1, cv::NORM_MINMAX, -1, cv::Mat()); - BLT_TRACE("Hello7"); - - auto comp = cv::compareHist(base_image_hist, hist, cv::HISTCMP_CORREL); - - fitness.standardized_fitness = fitness.raw_fitness / IMAGE_SIZE; - fitness.adjusted_fitness = (1.0 / (1.0 + fitness.standardized_fitness)) * comp; + fitness.raw_fitness = fitness_values[in]; + fitness.standardized_fitness = fitness.raw_fitness; + fitness.adjusted_fitness = (1.0 / (1.0 + fitness.standardized_fitness)); +// auto& v = fitness_data[in]; +// for (blt::size_t i = 0; i < DATA_SIZE; i++) +// { +// context ctx = get_ctx(i); +// v.gray_data[i] = static_cast(current_tree.get_evaluation_value(&ctx) * 255); +// +// auto dist = static_cast(v.gray_data[i]) - static_cast(base_data.rgb_data[i * CHANNELS + channel]); +// +// fitness.raw_fitness += std::sqrt(dist * dist); +// } +// cv::Mat img(IMAGE_SIZE, IMAGE_SIZE, CV_8UC1, v.gray_data.data()); +// cv::Mat img_rgb; +// cv::Mat img_hsv; +// cv::cvtColor(img, img_rgb, cv::COLOR_GRAY2RGB); +// cv::cvtColor(img_rgb, img_hsv, cv::COLOR_RGB2HSV); +// cv::Mat hist; +// cv::calcHist(&img_hsv, 1, channels, cv::Mat(), hist, 2, histSize, ranges, true, false); +// cv::normalize(hist, hist, 0, 1, cv::NORM_MINMAX, -1, cv::Mat()); +// +// auto comp = 1.0 - cv::compareHist(base_image_hist, hist, cv::HISTCMP_CHISQR); +// +// fitness.raw_fitness *= comp; + +// fitness.standardized_fitness = fitness.raw_fitness / IMAGE_SIZE; +// fitness.adjusted_fitness = (1.0 / (1.0 + fitness.standardized_fitness)); }; } -constexpr auto fitness_function_red = create_fitness_function(fitness_red, 0); +constexpr auto fitness_function_red = create_fitness_function(0); -constexpr auto fitness_function_green = create_fitness_function(fitness_green, 1); +constexpr auto fitness_function_green = create_fitness_function(1); -constexpr auto fitness_function_blue = create_fitness_function(fitness_blue, 2); +constexpr auto fitness_function_blue = create_fitness_function(2); + +void execute_generation(blt::gp::gp_program& program) +{ + BLT_TRACE("------------{Begin Generation %ld}------------", program.get_current_generation()); + BLT_START_INTERVAL("Image Test", "Gen"); + program.create_next_generation(blt::gp::select_tournament_t{}, blt::gp::select_tournament_t{}, blt::gp::select_tournament_t{}); + BLT_END_INTERVAL("Image Test", "Gen"); + BLT_TRACE("Move to next generation"); + BLT_START_INTERVAL("Image Test", "Fitness"); + program.next_generation(); + BLT_TRACE("Evaluate Fitness"); + program.evaluate_fitness(); + BLT_END_INTERVAL("Image Test", "Fitness"); + BLT_TRACE("----------------------------------------------"); + std::cout << std::endl; +} void evaluate_program(blt::gp::gp_program& program) { BLT_DEBUG("Begin Generation Loop"); while (!program.should_terminate()) { - BLT_TRACE("------------{Begin Generation %ld}------------", program.get_current_generation()); - BLT_START_INTERVAL("Image Test", "Gen"); - program.create_next_generation(blt::gp::select_tournament_t{}, blt::gp::select_tournament_t{}, blt::gp::select_tournament_t{}); - BLT_END_INTERVAL("Image Test", "Gen"); - BLT_TRACE("Move to next generation"); - BLT_START_INTERVAL("Image Test", "Fitness"); - program.next_generation(); - BLT_TRACE("Evaluate Fitness"); - program.evaluate_fitness(); - BLT_END_INTERVAL("Image Test", "Fitness"); - BLT_TRACE("----------------------------------------------"); - std::cout << std::endl; + execute_generation(program); } } @@ -332,9 +352,9 @@ void write_tree(blt::size_t index, blt::size_t best_red, blt::size_t best_blue, for (blt::size_t i = 0; i < DATA_SIZE; i++) { - found_data.image_data[i * CHANNELS] = fitness_red[best_red].image_data[i]; - found_data.image_data[i * CHANNELS + 1] = fitness_green[best_green].image_data[i]; - found_data.image_data[i * CHANNELS + 2] = fitness_blue[best_blue].image_data[i]; + found_data.rgb_data[i * CHANNELS] = generation_images[best_red].rgb_data[i * CHANNELS]; + found_data.rgb_data[i * CHANNELS + 1] = generation_images[best_green].rgb_data[i * CHANNELS + 1]; + found_data.rgb_data[i * CHANNELS + 2] = generation_images[best_blue].rgb_data[i * CHANNELS + 2]; } found_data.save("best_image_" + std::to_string(index) + ".png"); @@ -386,19 +406,27 @@ void make_operator_image(T op, Args... args) stbi_write_png((blt::type_string + ".png").c_str(), IMAGE_SIZE, IMAGE_SIZE, CHANNELS, value.get(), 0); } -int main() +void init(const blt::gfx::window_data&) { + using namespace blt::gfx; + + for (blt::size_t i = 0; i < config.population_size; i++) + { + gl_images.emplace_back(IMAGE_SIZE, IMAGE_SIZE, GL_RGB8); + resources.set(std::to_string(i), &gl_images.back()); + } + BLT_INFO("Starting BLT-GP Image Test"); BLT_INFO("Using Seed: %ld", SEED); BLT_START_INTERVAL("Image Test", "Main"); BLT_DEBUG("Setup Base Image"); base_data.load("../Rolex_De_Grande_-_Joo.png"); - cv::Mat base_image_mat{IMAGE_SIZE, IMAGE_SIZE, CV_8UC3, base_data.image_data.data()}; + cv::Mat base_image_mat{IMAGE_SIZE, IMAGE_SIZE, CV_8UC3, base_data.rgb_data.data()}; cv::cvtColor(base_image_mat, base_image_hsv, cv::COLOR_RGB2HSV); - cv::calcHist( &base_image_hsv, 1, channels, cv::Mat(), base_image_hist, 2, histSize, ranges, true, false ); - cv::normalize( base_image_hist, base_image_hist, 0, 1, cv::NORM_MINMAX, -1, cv::Mat() ); + cv::calcHist(&base_image_hsv, 1, channels, cv::Mat(), base_image_hist, 2, histSize, ranges, true, false); + cv::normalize(base_image_hist, base_image_hist, 0, 1, cv::NORM_MINMAX, -1, cv::Mat()); BLT_DEBUG("Setup Types and Operators"); type_system.register_type(); @@ -411,10 +439,55 @@ int main() program_red.generate_population(type_system.get_type().id(), fitness_function_red); program_green.generate_population(type_system.get_type().id(), fitness_function_green); program_blue.generate_population(type_system.get_type().id(), fitness_function_blue); + +// evaluate_program(program_red); +// evaluate_program(program_green); +// evaluate_program(program_blue); - evaluate_program(program_red); - evaluate_program(program_green); - evaluate_program(program_blue); + global_matrices.create_internals(); + resources.load_resources(); + renderer_2d.create(); +} + +void update(const blt::gfx::window_data& data) +{ + global_matrices.update_perspectives(data.width, data.height, 90, 0.1, 2000); + + camera.update(); + camera.update_view(global_matrices); + global_matrices.update(); + + for (blt::size_t i = 0; i < config.population_size; i++) + gl_images[i].upload(generation_images[i].rgb_data.data(), IMAGE_SIZE, IMAGE_SIZE, GL_RGB); + + if (ImGui::Begin("Program Control")) + { + ImGui::Button("Run Generation"); + if (ImGui::IsItemClicked()) + { + execute_generation(program_red); + execute_generation(program_green); + execute_generation(program_blue); + } + ImGui::End(); + } + + for (blt::size_t i = 0; i < config.population_size; i++) + { + renderer_2d.drawRectangleInternal(std::to_string(i), + {static_cast(IMAGE_SIZE * i), static_cast(IMAGE_SIZE * i), IMAGE_SIZE, IMAGE_SIZE}); + } + + renderer_2d.render(data.width, data.height); +} + +int main() +{ + blt::gfx::init(blt::gfx::window_data{"My Sexy Window", init, update}.setSyncInterval(1)); + global_matrices.cleanup(); + resources.cleanup(); + renderer_2d.cleanup(); + blt::gfx::cleanup(); BLT_END_INTERVAL("Image Test", "Main");