Конвертація відео файлу 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.: перший пост, не хочу просити про поблажливість. Навпаки: хочеться, щоб ви оцінили по всій строгості. Сподіваюся, ви напишете, що я накодил не так і щось порадите.

З повагою, Гаррі.

Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.