Конвертация видео файла в gif

от автора

Мой опыт программирования на с++ насчитывает 5 месяцев, до этого времени я около двух лет разрабатывал приложения для мобильных операционных систем. В один момент мне это надоело, и я решил, что пора начать осуществлять свою юношескую мечту — стать разработчиком игр. И я немного сменил направление движения своей карьеры.

Вот как-то я сидел и думал, что бы мне написать. Я выбрал для себя 16 программок, несколько раз подбросил монетку, и жребий указал мне на программку получения гифки из видео. Кто хочет увидеть дилетантский крестовый код — прошу под кат.

Принцип и структура очень простые. На вход нашей программе подается два параметра: путь до нашего видео и имя выходной гифки. Создаем экземпляр нашего простенького класса и вызываем метод создания гифки (забыл сказать, что будем использовать библиотеки OpenCv и Magick++).

Описание класса:

class Video{ public:   Video(const std::string& video_n, const std::string& gif_n){ video_name = video_n; output_gif_name = gif_n; };   ~Video() {};  void create_gif(); private:   std::string video_name;   std::string output_gif_name;   std::vector<Mat> frames;   std::vector<Magick::Image> Magick_frames;   void extract_frames();   static inline Magick::Image mat_2_magick(cv::Mat& src); }; 

Конструктор содержит два параметра — наши входные параметры из командной строки.

std::vector frames — свойство, которое содержит кадры нашего видео в структуре cv::Mat, std::vector<Magick::Image>.
Magick_frames — это свойство хранит преобразованные кадры.

Метод extract_frames вытягивает кадры из видео. Алгоритм очень простой и заключается в следующем:

1) создаем экземпляр класса cv::VideoCapture (класс для видео-захвата)
2) определяем счетчик кадров и запускаем цикл где будем обрабатывать видео
3) если наш счетчик не попадает в рамки нашего видео — выходим, иначе устанавливаем кадр VideoCapture равный нашему счетчику (свойство CV_CAP_PROP_POS_FRAMES)
4) пробуем считать кадр и если получается, то добавляем его в std::vector frames и увеличиваем счетчик кадров на 10 (каждый десятый кадр, что бы облегчить гифку)

void Video::extract_frames(){   try{     VideoCapture cap(this->video_name);     if (!cap.isOpened()) CV_Error(CV_StsError, "Can't open video file");     double fIdx = 0;     double frnb(cap.get(CV_CAP_PROP_FRAME_COUNT));    // std::cout << "frame count = " << frnb<< std::endl;     for (;;){      // std::cout<<"frame : "<<fIdx<<std::endl;       Mat frame;       if (fIdx < 0 || fIdx >= frnb) break;       cap.set(CV_CAP_PROP_POS_FRAMES, fIdx);       bool success = cap.read(frame);       if (success) { this->frames.push_back(frame); fIdx = fIdx + 10;}       else break;     }   }   catch(cv::Exception& e){     cerr << e.msg << std::endl;     exit(1);   } } 

В главно методе create_gif() мы сначала выполняем метод получения кадров, потом преобразуем эти кадры к структуре Magic::Image и записываем выходной файл.

Это метод для конвертации cv::Mat к Magic::Image. Это надо, потому что opencv не умеет работать с gif файлами, я нашел кучу библиотек, но решил остановиться на magick++.

*Если честно, я не ощутил компрессии и уменьшения качества до 50%, выходной файл, как с этими, так и без этих параметров весил одинаково*

inline Magick::Image Video::mat_2_magick(cv::Mat& src) {   Magick::Image mgk(src.cols, src.rows, "BGR", Magick::CharPixel, (char *)src.data);   mgk.compressType(JPEGCompression);   mgk.quality(50);   return mgk; }  void Video::create_gif() {   extract_frames();//так скорей всего не очень правильно делать   for(std::vector<cv::Mat>::iterator frame = this->frames.begin(); frame != this->frames.end(); ++frame){     this->Magick_frames.push_back(Video::mat_2_magick(*frame));   }   Magick::writeImages(this->Magick_frames.begin(), this->Magick_frames.end(), this->output_gif_name); } 

Немного расскажу про одну проблему, с которой я провозился до 7 утра. Я в этом проекте использовал CMake и я не указал флаги линковки и компиляции. Было довольно обидно, что я это упустил. Вот часть Cmake файла:

find_file(MAGICK_CONFIG_EXE "Magick++-config" PATHS     "/usr/bin"     "/usr/local/bin" ) if (MAGICK_CONFIG_EXE)   message(STATUS "Found Image Magick++ libaries -- Enabling MagickPainter.")   execute_process(COMMAND Magick++-config --cppflags OUTPUT_VARIABLE Magick_CPP_FLAGS OUTPUT_STRIP_TRAILING_WHITESPACE)   execute_process(COMMAND Magick++-config --cxxflags OUTPUT_VARIABLE Magick_CXX_FLAGS OUTPUT_STRIP_TRAILING_WHITESPACE)   execute_process(COMMAND Magick++-config --ldflags  OUTPUT_VARIABLE Magick_LD_FLAGS  OUTPUT_STRIP_TRAILING_WHITESPACE)   execute_process(COMMAND Magick++-config --libs     OUTPUT_VARIABLE Magick_LIBS      OUTPUT_STRIP_TRAILING_WHITESPACE)      set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Magick_CPP_FLAGS} ${Magick_CXX_FLAGS}")   set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${Magick_LIBS} ${Magick_LD_FLAGS}")       # remove_definitions(-DUSE_MAGICK_PAINTER) endif (MAGICK_CONFIG_EXE) 

Все есть на гите.

P.S.: первый пост, не хочу просить о снисхождении. Наоборот: хочется, чтобы вы оценили по всей строгости. Надеюсь, вы напишете, что я накодил не так и что-нибудь посоветуете.

С уважением, Гарри.

ссылка на оригинал статьи http://habrahabr.ru/post/269315/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *