Proof of Concept
von schorsch_76- SNIPPET_TEXT:
-
- #include <iostream>
- #include <future>
- #include <vector>
- #include <bitset>
- #include <optional>
- #include <sstream>
- #include <iomanip>
- #include "Vision/FrameGrabber.h"
- #include <opencv2/img_hash/phash.hpp>
- using HashValue_t = std::bitset<64>;
- struct SceneInfo {
- // this is a End Open Sequence [start,end[
- // excluding the end
- int64_t start_frame{};
- int64_t end_frame{};
- std::vector<HashValue_t> hashes{};
- };
- struct MovieInfo {
- fs::path file_path{};
- int64_t width{};
- int64_t height{};
- float fps{};
- int64_t frame_count{};
- std::vector<SceneInfo> scenes{};
- };
- size_t HammingDistance(const HashValue_t &v1, const HashValue_t &v2) {
- auto x = v1 ^ v2;
- return x.count();
- }
- MovieInfo ProcessFile(const fs::path &input_file) {
- const size_t hamming_distance_threshold = 10;
- const size_t min_scene_length = 25;
- Vision::FrameGrabber frame_grabber(input_file);
- auto hasher = cv::img_hash::PHash::create();
- MovieInfo ret{};
- ret.file_path = input_file;
- ret.width = frame_grabber.GetWidth();
- ret.height = frame_grabber.GetHeight();
- ret.fps = frame_grabber.GetFPS();
- ret.frame_count = frame_grabber.GetFrameCount();
- std::optional<HashValue_t> last_hash{};
- SceneInfo current_scene_info{};
- current_scene_info.start_frame = 0;
- while (frame_grabber.IsOk()) {
- auto frame = frame_grabber.Generate();
- cv::Mat out{};
- hasher->compute(frame, out);
- HashValue_t hash_value = out.at<uint64_t>(0, 0);
- // add the phash to the scene
- current_scene_info.end_frame = frame_grabber.GetPosition();
- current_scene_info.hashes.push_back(hash_value);
- if (!last_hash.has_value()) {
- last_hash = hash_value;
- assert(current_scene_info.hashes.size() ==
- static_cast<size_t>(current_scene_info.end_frame-current_scene_info.start_frame));
- } else {
- // check the hamming distance
- auto hamming_distance = HammingDistance(*last_hash, hash_value);
- last_hash = hash_value;
- if (hamming_distance > hamming_distance_threshold) {
- // we got a new scene
- // if this scene is too short, add it to the previous scene
- if (current_scene_info.hashes.size() < min_scene_length &&
- ret.scenes.size() > 0) {
- auto &last_scene_info = ret.scenes.back();
- last_scene_info.end_frame = current_scene_info.end_frame;
- for (auto &c: current_scene_info.hashes) {
- last_scene_info.hashes.push_back(c);
- }
- current_scene_info = SceneInfo{};
- current_scene_info.start_frame = frame_grabber.GetPosition();
- assert(last_scene_info.hashes.size() ==
- static_cast<size_t>(last_scene_info.end_frame-last_scene_info.start_frame));
- } else {
- assert(current_scene_info.end_frame > current_scene_info.start_frame);
- assert(current_scene_info.hashes.size() ==
- static_cast<size_t>(current_scene_info.end_frame-current_scene_info.start_frame));
- ret.scenes.push_back(current_scene_info);
- current_scene_info = SceneInfo{};
- current_scene_info.start_frame = frame_grabber.GetPosition();
- }
- }
- }
- }
- // add the last scene to the result
- current_scene_info.end_frame = frame_grabber.GetPosition();
- ret.scenes.push_back(current_scene_info);
- int64_t last_end = 0;
- for (auto &scene: ret.scenes) {
- assert(scene.start_frame == last_end);
- last_end = scene.end_frame;
- }
- return ret;
- }
- void DebugWrite(const MovieInfo &info, fs::path output_folder) {
- int s = 0;
- fs::create_directory(output_folder);
- Vision::FrameGrabber frame_grabber(info.file_path);
- for (auto &scene: info.scenes) {
- // get target filename
- std::ostringstream oss;
- oss << std::setw(5) << std::setfill('0') << std::setprecision(5) << std::fixed << s;;
- ++s;
- fs::path file = output_folder / (oss.str() + ".mp4");
- std::cout << "Writing: " << file.string() << std::endl;
- // open target file writer
- cv::VideoWriter writer(file.string(), cv::VideoWriter::fourcc('a','v','c','1'),
- info.fps, cv::Size(info.width, info.height), true);
- frame_grabber.SetPosition(scene.start_frame);
- for (int64_t pos = scene.start_frame; pos < scene.end_frame; pos++) {
- auto frame = frame_grabber.Generate();
- writer << frame;
- }
- }
- }
- int main(int argc, const char *argv[]) {
- if (argc < 3) {
- std::cerr << "Usage: " << argv[0] << " input_file1 input_file2" << std::endl;
- return EXIT_FAILURE;
- }
- try {
- fs::path input_file1 = argv[1];
- fs::path input_file2 = argv[2];
- if (!fs::exists(input_file1)) {
- std::cerr << "Input file 1 not found" << std::endl;
- return EXIT_FAILURE;
- }
- if (!fs::exists(input_file2)) {
- std::cerr << "Input file 2 not found" << std::endl;
- return EXIT_FAILURE;
- }
- auto a1 = std::async(std::launch::async, ProcessFile, input_file1);
- auto a2 = std::async(std::launch::async, ProcessFile, input_file2);
- auto info1 = a1.get();
- auto info2 = a2.get();
- DebugWrite(info1, "/tmp/input1");
- DebugWrite(info2, "/tmp/input2");
- return EXIT_SUCCESS;
- } catch (const std::exception &e) {
- std::cerr << e.what() << std::endl;
- }
- return EXIT_FAILURE;
- }
Quellcode
Hier kannst du den Code kopieren und ihn in deinen bevorzugten Editor einfügen. PASTEBIN_DOWNLOAD_SNIPPET_EXPLAIN