#include #include #include #include #include #include #include #include #include extern "C" { #include #include } #include #include #include static const int tile_width = 500; static const int tile_height = 500; using namespace std; using Metric = fingerprints::rgb; using Database = image_database; static auto calculate_all_distances(Database const & db, string const & filename, int h_tiles, int v_tiles){ using return_type = decltype(db.distances_for_image(std::declval())); Mozaic mozaic(h_tiles, v_tiles); apply_to_tiles(filename, h_tiles, v_tiles, [&](int c, int r, av::frame const & frame){ mozaic[r][c] = db.distances_for_image(frame); }); return mozaic; } template static void save_mozaic(Mozaiq const & mozaic, string filename){ auto const pix_fmt = AV_PIX_FMT_YUVJ444P; auto const total_width = mozaic.h_tiles * tile_width; auto const total_height = mozaic.v_tiles * tile_height; // Create output frame const auto frame_data = [=]{ std::vector> data(make_u(avpicture_get_size(pix_fmt, total_width, total_height)), 0); auto frame = av::frame_alloc(); avpicture_fill(reinterpret_cast(frame.get()), data.data(), pix_fmt, total_width, total_height); frame->width = total_width; frame->height = total_height; frame->format = pix_fmt; return std::make_pair(std::move(frame), std::move(data)); }(); const auto & frame = frame_data.first; // For each tile: get the part, copy input to it av::frame frame_part = av::frame_clone(frame); frame_part->width = tile_width; frame_part->height = tile_height; for(int r = 0; r < mozaic.v_tiles; ++r) { for(int c = 0; c < mozaic.h_tiles; ++c){ av_picture_crop(reinterpret_cast(frame_part.get()), reinterpret_cast(frame.get()), av::get_format(frame), r * tile_height, c * tile_width); auto const input = crop_to_square(open_image(mozaic[r][c])); auto context = sws::create_context(input, frame_part); sws::scale(context, input, frame_part); } } encode_as_jpg(frame, filename); } int main(int argc, char *argv[]){ if(argc != 6){ cerr << "usage: main \n"; return 1; } av_register_all(); av_log_set_level(AV_LOG_QUIET); // TODO: use boost::program_options string const database_directory = argv[1]; string const filename = argv[2]; string const output = argv[3]; int const h_tiles = stoi(argv[4]); int const v_tiles = stoi(argv[5]); auto const db = read_database(database_directory); cout << colors::green("Read database: ") << db.size() << endl; auto const distances = calculate_all_distances(db, filename, h_tiles, v_tiles); cout << colors::green("Calculated distances for ") << filename << endl; auto const best_indices = optimize_unique(distances); cout << colors::green("Picked best distances") << endl; auto const mozaic = mozaic_fmap(best_indices, [&](auto i){ return db.filename(i); }); cout << colors::green("Picked filenames") << endl; save_mozaic(mozaic, output); cout << colors::green("Saved Mozaic to ") << output << endl; }