複数枚の画像を動画にしたいな~って時ありません?
(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 : このファイルには '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]
に入ってくるのでそれを利用して中の連番画像を順に読み込んでいきます
#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.h
にtime.h
をインクルードして
#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を用意して各フレームを代入していき動画を出力します
最終的なプログラムがこちらです↓
#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では問題なく動くのでできたもんだと思ってますがぜひおかしなところとかあれば何かコメント等いただけると幸いです
ではでは!