From 14234735c64523f48025e40722b403ab446ad001 Mon Sep 17 00:00:00 2001 From: Deukhoofd Date: Sun, 16 Jan 2022 13:18:17 +0100 Subject: [PATCH] Remove dependency on opencv on Linux, fixes for Epsilon --- .idea/vcs.xml | 6 -- CMakeLists.txt | 13 ++-- CMakeLists.txt.in | 37 +++++++++++ demo/main.cpp | 94 +++++++++++++++++---------- demo/options.h | 8 +-- src/EpsilonHook.cpp | 155 +++++++++++++++++++++++++++++++++++--------- src/morph.cpp | 4 +- 7 files changed, 235 insertions(+), 82 deletions(-) delete mode 100644 .idea/vcs.xml create mode 100644 CMakeLists.txt.in diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100644 index 94a25f7..0000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 9496856..5c357b6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,12 +4,11 @@ project("atomorph") set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) -add_compile_options(-Wall -Wextra -Werror) - option(WINDOWS "Whether the build target is Windows or not." OFF) option(SHARED "Whether we should build a shared library, instead of a static one." OFF) option(DEMO "Whether or not the demo should be built." OFF) option(OPENCV "Whether or not opencv should be targeted." OFF) +option(STATICC "Whether or not dependencies should be statically linked." ON) if (NOT WINDOWS) set(CMAKE_POSITION_INDEPENDENT_CODE ON) @@ -43,15 +42,21 @@ endif (WINDOWS) if (STATICC) message("Linking dependencies statically.") set (CMAKE_SHARED_LINKER_FLAGS "-Wl,--as-needed") - set(LINKS -static-libgcc -static-libstdc++ -Wl,-Bstatic -lm -lstdc++ -lpthread -Wl,-Bdynamic ${LINKS}) + set(LINKS -lm -lpthread -static-libgcc -static-libstdc++ -Wl,-Bstatic -lstdc++ -Wl,-Bdynamic ${LINKS}) endif(STATICC) if (OPENCV) + include(CMakeLists.txt.in) + include_opencv() find_package( OpenCV REQUIRED ) include_directories( ${OpenCV_INCLUDE_DIRS} ) add_definitions(-D ATOMORPH_OPENCV) - set(LINKS ${LINKS} ${OpenCV_LIBS}) + if (STATICC) + set(LINKS ${LINKS} -Wl,-Bstatic opencv_core opencv_flann -Wl,-Bdynamic) + else() + set(LINKS ${LINKS} ${OpenCV_LIBS}) + endif() endif() target_link_libraries(atomorph ${LINKS}) diff --git a/CMakeLists.txt.in b/CMakeLists.txt.in new file mode 100644 index 0000000..9addc15 --- /dev/null +++ b/CMakeLists.txt.in @@ -0,0 +1,37 @@ +cmake_minimum_required(VERSION 2.8.12) + +project(atomorph-download NONE) + +include(ExternalProject) +ExternalProject_Add(opencv + GIT_REPOSITORY https://github.com/opencv/opencv.git + GIT_TAG 4.x + PREFIX "${CMAKE_CURRENT_BINARY_DIR}/opencv" + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND "" + TEST_COMMAND "" + ) + +function(include_opencv) + configure_file(CMakeLists.txt.in opencv/download/CMakeLists.txt) + execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" . -DBUILD_SHARED_LIBS:BOOL=OFF + RESULT_VARIABLE result + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/opencv/download) + if (result) + message(FATAL_ERROR "CMake step for opencv failed: ${result}") + endif () + execute_process(COMMAND ${CMAKE_COMMAND} --build . + RESULT_VARIABLE result + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/opencv/download) + if (result) + message(FATAL_ERROR "Build step for opencv failed: ${result}") + endif () + + add_subdirectory(${CMAKE_CURRENT_BINARY_DIR}/opencv/src/opencv + ${CMAKE_CURRENT_BINARY_DIR}/opencv/bin + EXCLUDE_FROM_ALL) + + set( OPENCV_ROOT_DIR ${CMAKE_BINARY_DIR}/INSTALL ) + set( OPENCV_DIR ${CMAKE_BINARY_DIR}/INSTALL ) +endfunction() \ No newline at end of file diff --git a/demo/main.cpp b/demo/main.cpp index e70fd30..6af3d91 100644 --- a/demo/main.cpp +++ b/demo/main.cpp @@ -1,14 +1,14 @@ /* * See Copyright Notice in main.h */ -#include -#include -#include -#include - #include "main.h" -#include "lodepng.h" +#include +#include +#include +#include +#include #include "../src/atomorph.h" +#include "lodepng.h" MORPH_OPTIONS options; @@ -29,28 +29,28 @@ int main(int argc, char **argv) { // Options should be set before any operations with // the morph instance. However, they can be changed // during the run time too. - morph.set_blob_delimiter (options.differ_blobs); - morph.set_blob_max_size (options.blob_max_size); - morph.set_blob_min_size (options.blob_min_size); - morph.set_blob_box_grip (options.blob_box_grip); - morph.set_blob_box_samples(options.blob_box_samples); - morph.set_blob_threshold (options.blob_threshold); - morph.set_blob_number (options.blob_number); - morph.set_seed (options.seed); - morph.set_blob_rgba_weight(options.blob_rgba_weight); - morph.set_blob_size_weight(options.blob_size_weight); - morph.set_blob_xy_weight (options.blob_xy_weight); - morph.set_degeneration (options.degenerate); - morph.set_density (options.density); // Higher than 1 sets fluid to 0. - morph.set_motion (options.motion); - morph.set_fading (options.fading); - morph.set_threads (options.threads); - morph.set_cycle_length (options.cycle_length); - morph.set_feather (options.feather); - morph.set_keep_background (options.keep_background); - morph.set_finite (options.finite); - morph.set_show_blobs (options.show_blobs); - morph.set_fluid (options.fluid); // Higher than 0 sets density to 1. + morph.set_blob_delimiter(am::HSP); + morph.set_blob_max_size(SIZE_MAX); + morph.set_blob_min_size(1); + morph.set_blob_box_grip(UINT16_MAX); + morph.set_blob_box_samples(100); + morph.set_blob_threshold(1.0); + morph.set_blob_number(1); + morph.set_seed(0); + morph.set_blob_rgba_weight(1); + morph.set_blob_size_weight(0); + morph.set_blob_xy_weight(0); + morph.set_degeneration(10000); + morph.set_density(2); // Higher than 1 sets fluid to 0. + morph.set_motion(am::SPLINE); + morph.set_fading(am::PERLIN); + morph.set_threads(8); + morph.set_cycle_length(100000); + morph.set_feather(0); + morph.set_keep_background(0); + morph.set_finite(1); + morph.set_show_blobs(am::TEXTURE); + morph.set_fluid(0); // Higher than 0 sets density to 1. if (!load_files(&morph)) return -1; @@ -143,15 +143,39 @@ bool load_files(am::morph *morph) { // Load input image files: for (i=0; i(stream), + std::istream_iterator()); + width = image[0]; + height = image[1]; + image.erase(image.begin()); + image.erase(image.begin()); + std::string buf_o = "foo_"; + buf_o += std::to_string(i); + buf_o += ".png"; + error = lodepng::encode(buf_o, image, width, height); + if (error) { + std::cerr << lodepng_error_text(error) << "." << std::endl; + //return false; + } } - + else{ + error = lodepng::decode(image, width, height, buf.c_str()); + if (error) { + std::cerr << lodepng_error_text(error) << "." << std::endl; + return false; + } + } + max_width = std::max(max_width, width); max_height = std::max(max_height, height); diff --git a/demo/options.h b/demo/options.h index 9d461aa..2737a8b 100644 --- a/demo/options.h +++ b/demo/options.h @@ -41,11 +41,11 @@ class MORPH_OPTIONS { int width = 0; unsigned seed = 0; unsigned frames_out= 0; - unsigned match_time= 1; - unsigned morph_time= 3; - unsigned feather = 0; + unsigned match_time= 0; + unsigned morph_time= 0; + unsigned feather = 1; unsigned fluid = 0; - + unsigned cycle_length=100000; unsigned threads =8; diff --git a/src/EpsilonHook.cpp b/src/EpsilonHook.cpp index 77f0d58..de2508d 100644 --- a/src/EpsilonHook.cpp +++ b/src/EpsilonHook.cpp @@ -2,49 +2,142 @@ #define export extern "C" [[maybe_unused]] -export am::morph* create_morph(uint16_t width, uint16_t height, uint8_t img_a[], uint8_t img_b[]) { +static bool set_morph_frame(am::morph* morph, size_t frame, uint16_t width, const std::vector& image) { + auto sz = image.size(); + unsigned char r = 0, g = 0, b = 0, a = 0; + size_t pixel = 0; + + if (width > UINT16_MAX) + return false; + + for (size_t j = 0; j < sz; ++j) { + switch (j % 4) { + case 0: r = image.at(j); break; + case 1: g = image.at(j); break; + case 2: b = image.at(j); break; + default: { + a = image.at(j); + + if (a == 0) { + pixel++; + continue; + } + morph->add_pixel(frame, am::create_pixel(pixel % width, pixel / width, r, g, b, a)); + pixel++; + break; + } + } + } + return true; +} + +export am::morph* create_morph(uint16_t width, uint16_t height, uint8_t img_a[], + uint8_t img_b[]) { auto* morph = new am::morph(); - morph->set_blob_delimiter (am::HSP); - morph->set_blob_max_size (128); - morph->set_blob_min_size (3); - morph->set_blob_box_grip (16); - morph->set_blob_box_samples(-1); - morph->set_blob_threshold (128); - morph->set_blob_number (1); - morph->set_seed (0); + morph->set_blob_delimiter(am::HSP); + morph->set_blob_max_size(SIZE_MAX); + morph->set_blob_min_size(1); + morph->set_blob_box_grip(UINT16_MAX); + morph->set_blob_box_samples(100); + morph->set_blob_threshold(1.0); + morph->set_blob_number(1); + morph->set_seed(0); morph->set_blob_rgba_weight(1); morph->set_blob_size_weight(0); - morph->set_blob_xy_weight (0); - morph->set_degeneration (10000); - morph->set_density (2); // Higher than 1 sets fluid to 0. - morph->set_motion (am::SPLINE); - morph->set_fading (am::PERLIN); - morph->set_threads (8); - morph->set_cycle_length (100000); - morph->set_feather (0); - morph->set_keep_background (0); - morph->set_finite (1); - morph->set_show_blobs (am::TEXTURE); - morph->set_fluid (0); // Higher than 0 sets density to 1. - + morph->set_blob_xy_weight(0); + morph->set_degeneration(10000); + morph->set_density(2); // Higher than 1 sets fluid to 0. + morph->set_motion(am::SPLINE); + morph->set_fading(am::PERLIN); + morph->set_threads(16); + morph->set_cycle_length(100000); + morph->set_feather(0); + morph->set_keep_background(0); + morph->set_finite(1); + morph->set_show_blobs(am::TEXTURE); + morph->set_fluid(0); // Higher than 0 sets density to 1. morph->set_resolution(width, height); - for (int i = 0; i < width * height; i++) { - auto real_index = i * 4; - morph->add_pixel(0, am::create_pixel(i % width, i / width, img_a[real_index], img_a[real_index + 1], - img_a[real_index + 2], img_a[real_index + 3])); - } - for (int i = 0; i < width * height; i++) { - auto real_index = i * 4; - morph->add_pixel(1, am::create_pixel(i % width, i / width, img_b[real_index], img_b[real_index + 1], - img_b[real_index + 2], img_b[real_index + 3])); + + auto i1 = std::vector(img_a, img_a + width * height * 4); + auto i2 = std::vector(img_b, img_b + width * height * 4); + auto success = set_morph_frame(morph, 0, width, i1) && set_morph_frame(morph, 1, width, i2); + if (!success) { + return nullptr; } morph->compute(); + while (true) { + morph->suspend(); + morph->synchronize(); + morph->compute(); + auto state = morph->get_state(); + if (state > am::STATE_BLOB_UNIFICATION) { + break; + } + } return morph; } +export void run_blob_matching(am::morph* morph, size_t ms) { + std::chrono::steady_clock::time_point start, now; + start = std::chrono::steady_clock::now(); + while (true) { + morph->suspend(); + morph->synchronize(); + morph->compute(); + auto state = morph->get_state(); + if (state < am::STATE_BLOB_MATCHING) { + continue; + } + now = std::chrono::steady_clock::now(); + if ((size_t)std::chrono::duration_cast(now - start).count() >= ms) { + morph->next_state(); + break; + } + } + auto state = morph->get_state(); + while (state < am::STATE_ATOM_MORPHING) { + morph->suspend(); + morph->synchronize(); + morph->compute(); + state = morph->get_state(); + } +} +export void finish_atom_matching(am::morph* morph) { + morph->suspend(); + auto state = morph->get_state(); + while (state < am::STATE_ATOM_MORPHING) { + morph->suspend(); + morph->synchronize(); + morph->compute(); + state = morph->get_state(); + } + + morph->next_state(); +} + +export void get_frame(am::morph* morph, size_t frame, size_t total_frames, uint32_t width, uint32_t height, + uint8_t out[]) { + double t = morph->get_time(frame, total_frames); + std::vector pixels; + morph->get_pixels(t, &pixels); + auto size = width * height * 4; + while (!pixels.empty()) { + am::pixel px = pixels.back(); + pixels.pop_back(); + + size_t pos = ((size_t)px.y * width + (size_t)px.x) * 4; + if (pos >= size) + continue; + + out[pos + 0] = px.c.r; + out[pos + 1] = px.c.g; + out[pos + 2] = px.c.b; + out[pos + 3] = px.c.a; + } +} export void delete_morph(am::morph* morph) { delete morph; } \ No newline at end of file diff --git a/src/morph.cpp b/src/morph.cpp index 5a0af5d..8984f80 100644 --- a/src/morph.cpp +++ b/src/morph.cpp @@ -939,7 +939,7 @@ void morph::step_fluid(size_t frame_key, double t, double time) { // All sources are already occupied, this new particle must now // share the source with some other particle, but it will still // must get an unused destination. Search for such destination. - bool destination_found = false; + [[maybe_unused]] bool destination_found = false; for (it=destinations.begin(); it!=destinations.end(); ++it) { size_t pos = it->first; size_t x = it->second; @@ -954,7 +954,7 @@ void morph::step_fluid(size_t frame_key, double t, double time) { p->destination_pos = pos; particles_by_destination[pos].push_back(p); destination_found = true; - + { // Destination was found but all the sources were already // occupied. Now see the pt1 of this destination even if