/* * See Copyright Notice in main.h */ #include "main.h" #include #include #include #include #include #include "../src/atomorph.h" #include "lodepng.h" MORPH_OPTIONS options; int main(int argc, char **argv) { if (!init(argc, argv)) { fprintf(stderr, "Failed to initialize!\n"); return -1; } if (options.exit_flag) return 0; std::chrono::steady_clock::time_point program_start; std::chrono::steady_clock::time_point program_end; program_start = std::chrono::steady_clock::now(); { am::morph morph; // 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(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; main_loop (&morph); save_files(&morph); } program_end = std::chrono::steady_clock::now(); if (options.verbose) { size_t duration = std::chrono::duration_cast(program_end - program_start).count(); if (duration < 1000) printf("Process took %lu microseconds to finish.\n", duration); else if (duration < 1000000) printf("Process took %lu milliseconds to finish.\n", duration/1000); else printf("Process took %lu seconds to finish.\n", duration/1000000); } return 0; } bool init(int argc, char **argv) { if (true == (am::get_warning()&am::WARN_POINTER_SIZE)) { fprintf(stderr, "Pointer size is insufficiently small.\n"); } if (true == (am::get_warning()&am::WARN_PIXEL_SIZE)) { fprintf(stderr, "Pixel size (%lu) is larger than optimal (%lu).\n", sizeof(am::pixel), sizeof(void *) ); } if (true == (am::get_warning()&am::WARN_POINT_SIZE)) { fprintf(stderr, "Point size (%lu) is larger than optimal (%lu).\n", sizeof(am::point), sizeof(void *) ); } if (am::uses_opencv()) { fprintf(stderr, "Experimental OpenCV optimizations are enabled.\n"); } if (argc == 1) { fprintf(stderr, "No arguments specified, try \"\e[1;33m%s --help\e[0m\".\n", argv[0]); } return options.parse(argc, argv); } bool fill_morph(am::morph *morph, size_t frame, std::vector *image, unsigned width) { size_t sz = image->size(); unsigned char r=0,g=0,b=0,a=0; size_t pixel = 0; bool empty = true; if (width > UINT16_MAX) return false; for (size_t j=0; jat(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++; empty = false; break; } } } if (empty) morph->add_frame(frame); return true; } void save_files(am::morph *morph) { for (unsigned f = 0; fget_width(), morph->get_height()); } } bool load_files(am::morph *morph) { std::string buf; std::vector image; unsigned width, height, error; unsigned max_width=0, max_height=0; image.reserve(262144); size_t i; // 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); if (options.verbose) printf("%ux%u image decoded.\n", width, height); if (!fill_morph(morph, i, &image, width) && options.verbose) { printf("Unable to fill %lu. frame.\n", i); } image.clear(); } if (morph->get_frame_count()==0) { fprintf(stderr, "Error. Morph does not contain any key frames.\n"); return false; } width = max_width; height= max_height; morph->set_resolution(width, height); return true; } void write_image(am::morph *morph, size_t frame_out, unsigned width, unsigned height) { double t = morph->get_time(frame_out, options.frames_out); char buf[1024]; sprintf(buf, "%s/%s_%04lu.png", options.outdir.c_str(), options.file.c_str(), frame_out+1); if (options.verbose) printf("Rendering %4lu. frame ... ", frame_out+1); std::vector image; image.reserve(4*width*height); image.resize (4*width*height, 0); std::vector pixels; morph->get_pixels(t, &pixels); while (!pixels.empty()) { am::pixel px = pixels.back(); pixels.pop_back(); size_t pos = (px.y*width + px.x)*4; if (pos >= image.size()) continue; image[pos + 0] = px.c.r; image[pos + 1] = px.c.g; image[pos + 2] = px.c.b; image[pos + 3] = px.c.a; } if (options.verbose) printf("writing %s ... ", buf); unsigned error = lodepng::encode(buf, image, width, height); if (error) { if (options.verbose) printf("[\e[1;31mFAIL\e[0m]\n"); std::cerr << "encoder error " << error << ": "<< lodepng_error_text(error) << std::endl; } else if (options.verbose) printf("[\e[1;32mDONE\e[0m]\n"); } void main_loop(am::morph *morph) { if (options.verbose) { printf("Blobifying %ux%u morph.\n", morph->get_width(), morph->get_height()); } std::chrono::steady_clock::time_point start,end; start = std::chrono::steady_clock::now(); size_t blob_count = 0; size_t largest_frame = 0; double last_energy = 0.0; size_t match_blobs = 0; size_t morph_atoms = 0; size_t fs = options.files.size(); while (1) { morph->suspend(); morph->synchronize(); morph->compute(); blob_count = 0; for (size_t i=0; iget_blob_count(i); if (bc >= blob_count) { blob_count = bc; largest_frame = i; } } unsigned morph_state = morph->get_state(); end = std::chrono::steady_clock::now(); if (std::chrono::duration_cast(end - start).count() > 1000) { if (morph_state == am::STATE_BLOB_DETECTION || morph_state == am::STATE_BLOB_UNIFICATION) { if (options.verbose) { printf("%lu/%lu blob%s remaining on frame %lu.\n", blob_count, morph->get_blob_count(), blob_count == 1 ? "" : "s", largest_frame ); } } else if (morph_state == am::STATE_BLOB_MATCHING) { if (options.verbose) { double e = morph->get_energy(); if (last_energy < e) printf("Matching blobs, absolute energy was %30.10f.\n", e); else printf("Matching blobs, energy decreased by %30.10f.\n", last_energy - e); last_energy = e; } if (++match_blobs >= options.match_time) { morph->next_state(); last_energy = 0.0; } } else if (morph_state == am::STATE_ATOM_MORPHING) { if (options.verbose) { double e = morph->get_energy(); if (last_energy < e) printf("Matching atoms, absolute energy was %30.2f.\n", e); else printf("Matching atoms, energy decreased by %30.2f.\n", last_energy - e); last_energy = e; } if (++morph_atoms >= options.morph_time) { morph->next_state(); } } else if (morph_state == am::STATE_DONE) { if (options.verbose) printf("All done!\n"); break; } else { if (options.verbose) printf("Unknown state!\n"); break; } start = std::chrono::steady_clock::now(); } std::this_thread::sleep_for(std::chrono::milliseconds(100)); } if (options.verbose) { printf("Frame %lu had the most blobs (%lu).\n", largest_frame, blob_count); } return; }