/* * See Copyright Notice in main.h */ #include #include #include #include #include "main.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 (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. 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; iget_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; }