LoginSignup
1
0

More than 3 years have passed since last update.

連番画像を動画化する(C++,OpenCV)

Posted at

複数枚の画像を動画にしたいな~って時ありません?
(aviutlとかでできそ~って感じもするんですが)
(調べてないんで分かりませんが)
複数枚の連番画像が入ったフォルダをD&Dするだけで順番に表示して動画化してくれるやつ欲しいな~って…
私はありますのでひぃひぃ言いながらプログラムを書きました
自分用メモ書きです
あっそういえば使ってるのはVisualStudio2017です

コマンドライン引数

コマンドライン引数ってなんぞや?
ってぐらいレベルの低い人で申し訳ないんですけど…
exeにD&Dしてぱ~っってなるやつ(雑)私もやりたくて調べたらコマンドライン引数って出てきました
なんでもexeはそのまま与えるファイルパスだけ変えられるんだとか
へぇ~なんか知らんけど聞いたことある~!やってみよ!
早速やってみます

まずは簡単に

コマンドライン引数を使うにはメイン文をint main(int argc, char *argv[])で始める
int argcは引数の数
char * argv[]は引数として受け取った値が入る
argvの一つ目の値にはプログラム自身の名前が入る

ふーん…なんかよくわからんけどmainの括弧のところにint argc, char *argv[]って書いたらいいのね~おっけ~

pic_to_video.cpp
// Pic to Video.cpp : このファイルには 'main' 関数が含まれています。プログラム実行の開始と終了がそこで行われます。
//

#include "pch.h"
#include <iostream>

int main(int argc, char *argv[])
{
    std::cout << "Hello World!\n"; 
    std::cout << argc << std::endl;
    for (int i = 0; i < argc; i++) {
        std::cout << argv[i] << std::endl;
    }

    system("pause");

    return 0;
}

とりあえずF5してみます

実行結果

Hello World!
1
C:\Users\~~~\pic_to_video.exe
続行するには何かキーを押してください . . .

ん~なるほど?
引数は1つでその引数の中身はたしかにプログラムの名前が入ってる

ここでできたexeファイルに適当に作ったフォルダ(C:\Users~~~\test)をD&Dしてみると

実行結果

Hello World!
2
C:\Users\~~~\pic_to_video.exe
C:\Users\~~~\test
続行するには何かキーを押してください . . .

ばっちり引数2個になりました!
そして一つ目の値にはプログラムの名前、二つ目の値にはD&Dしたフォルダのパスが入りました
わーいわーい!俄然楽しくなってきました
これでフォルダに入ってる画像の読み込みできそうです

連番画像の読み込み

D&Dしたフォルダパスがargv[1]に入ってくるのでそれを利用して中の連番画像を順に読み込んでいきます

pic_to_video.cpp
#include "pch.h"
#include <iostream>

int main(int argc, char *argv[])
{
    std::cout << "Hello World!\n"; 
    std::cout << argc << std::endl;
    for (int i = 0; i < argc; i++) {
        std::cout << argv[i] << std::endl;
    }

    if (argc == 2) {
        char filename[100];
        strcpy_s(filename, argv[1]);
        char inname[100];
        cv::Mat img;
        for (int time = 0;;) {
            sprintf_s(inname, 100, "%s/%d.bmp", filename, time);
            img = cv::imread(inname);
            if (img.data == NULL)   break;
            time++;
        }
    }
    else {
        std::cout << "D&Dで動画化したいフォルダを読み込んでください" << std::endl;
    }

    system("pause");

    return 0;
}

timeって書いてるんですがflameとかのが分かりやすいかもですね
これでフォルダ名/0.bmpから順に1.bmp,2.bmp…と連番画像を読み込んでcv::Mat imgに代入することができます
あとは動画を作って保存するだけです

日付の取得

さて動画を作って保存したいわけですが作った動画につける名前で悩みます
プログラム作ったらフォルダをD&Dしてひゅーっぽいっじゃーん動画できた!次はこっちのフォルダ!ぽいっ!できた!よし二つの動画を見比べよう!みたいなことがわたくしはやりたかったわけです
そこで作成された動画は違う名前になってほしい…
自然に「それじゃあ実行したときの時間にしようかな」ってなりました
他にもっと頭いい方法があっても知らんわ…むしろ教えて…

さてpch.htime.hをインクルードして

pic_to_video.cpp
#include "pch.h"
#include <iostream>

int main(int argc, char *argv[])
{
    std::cout << "Hello World!\n"; 
    std::cout << argc << std::endl;
    for (int i = 0; i < argc; i++) {
        std::cout << argv[i] << std::endl;
    }

    if (argc == 2) {
        time_t now = time(NULL);
        errno_t error;
        struct tm pnow;
        error = localtime_s(&pnow, &now);
        char year[50];  sprintf_s(year, 50, "%4d", pnow.tm_year + 1900);
        char mon[50];   sprintf_s(mon, 50, "%02d", pnow.tm_mon + 1);
        char day[50];   sprintf_s(day, 50, "%02d", pnow.tm_mday);
        char hour[50];  sprintf_s(hour, 50, "%02d", pnow.tm_hour);
        char min[50];   sprintf_s(min, 50, "%02d", pnow.tm_min);
        strcat_s(year, mon);
        strcat_s(year, day);
        strcat_s(year, hour);
        strcat_s(year, min);
        std::cout << year << std::endl;

        char filename[100];
        strcpy_s(filename, argv[1]);
        char inname[100];
        cv::Mat img;
        for (int time = 0;;) {
            sprintf_s(inname, 100, "%s/%d.bmp", filename, time);
            img = cv::imread(inname);
            if (img.data == NULL)   break;
    }
    else {
        std::cout << "D&Dで動画化したいフォルダを読み込んでください" << std::endl;
    }

    system("pause");

    return 0;
}

これでyearに現在時刻が入ります
sprintfとかstrcatとかvisual studioで使うと怒られるんでsprintf_sとかstrcat_sを使ってます

これを用いて出力する動画をyearに入ってる文字列.aviにすることにします
次はいよいよ動画出力です

動画出力

char outname[100]を用意してyear.aviを作ります
wrtを用意して各フレームを代入していき動画を出力します
最終的なプログラムがこちらです↓

pic_to_video.cpp
#include "pch.h"
#include <iostream>

int main(int argc, char *argv[])
{
    std::cout << "Hello World!\n"; 
    std::cout << argc << std::endl;
    for (int i = 0; i < argc; i++) {
        std::cout << argv[i] << std::endl;
    }

    if (argc == 2) {
        time_t now = time(NULL);
        errno_t error;
        struct tm pnow;
        error = localtime_s(&pnow, &now);
        char year[50];  sprintf_s(year, 50, "%4d", pnow.tm_year + 1900);
        char mon[50];   sprintf_s(mon, 50, "%02d", pnow.tm_mon + 1);
        char day[50];   sprintf_s(day, 50, "%02d", pnow.tm_mday);
        char hour[50];  sprintf_s(hour, 50, "%02d", pnow.tm_hour);
        char min[50];   sprintf_s(min, 50, "%02d", pnow.tm_min);
        strcat_s(year, mon);
        strcat_s(year, day);
        strcat_s(year, hour);
        strcat_s(year, min);
        std::cout << year << std::endl;

        cv::namedWindow(year, CV_WINDOW_AUTOSIZE);
        double fps = 30;

        char filename[100];
        strcpy_s(filename, argv[1]);
        std::cout << filename << std::endl;
        char inname[100];
        sprintf_s(inname, 100, "%s/1.bmp", filename);
        cv::Mat input = cv::imread(inname, CV_LOAD_IMAGE_COLOR);
        char outname[100];
        sprintf_s(outname, 100, "%s.avi", year);
        cv::VideoWriter wrt(outname, -1, fps, cv::Size(input.cols, input.rows));
        if (!wrt.isOpened()) {
            std::cout << "video write error\n" << std::endl;
            system("pause");
            return -1;
        }
        cv::Mat img;
        for (int time = 0;;) {
            sprintf_s(inname, 100, "%s/%d.bmp", filename, time);
            img = cv::imread(inname);
            if (img.data == NULL)   break;
            cv::imshow(filename, img);
            char code;
            code = cv::waitKey(10);
            wrt << img;
            time++;
        }
        cv::destroyWindow(filename);
    }
    else {
        std::cout << "D&Dで動画化したいフォルダを読み込んでください" << std::endl;
    }

    system("pause");

    return 0;
}

できた~!
わたしのPCでは問題なく動くのでできたもんだと思ってますがぜひおかしなところとかあれば何かコメント等いただけると幸いです

ではでは!

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0