OpenCV 2.0 で映像ファイルを連番をつけて静止画像に分解・保存する

  • pbm は作成方法が分からなかった
  • 10000枚ごとにフォルダ分けする

video2still.cpp

#include <opencv/cv.h>
#include <opencv/highgui.h>
#include <stdio.h>
#include <malloc.h>
#include <errno.h>
#include <direct.h>

#ifdef _DEBUG
#pragma comment( lib, "cv200d.lib" )
#pragma comment( lib, "cxcore200d.lib" )
#pragma comment( lib, "highgui200d.lib" )
#else
#pragma comment( lib, "cv200.lib" )
#pragma comment( lib, "cxcore200.lib" )
#pragma comment( lib, "highgui200.lib" )
#endif

//! ファイル名バッファサイズ
const size_t BUFFERSIZE_FILENAME = 250;

//! フォルダ分けの是非
bool flag_nosplit = false;
//! フォルダ分けフラグを左右する文字列
const char OPTION_NOSPLIT[] = "/nosplit";
//! フォルダ分け画像単位
const int OUTSTILL_UNIT = 10000;
//! 対応拡張子文字列.doc/opencv.pdf p,837 から
const char *EXTENSIONS[] = { 
	"bmp", "dib", //!< Windows bitmaps
	"jpeg", "jpg", "jpe", //!< JPEG files
	"jp2", //!< JPEG 2000
	"png", //!< Portable Network Graphics
	/* "pbm", */ "pgm", "ppm", //!< Portable image format
	"sr", "ras",  // Sun rasters
	"tiff", "tif", //!< TIFF files
	NULL,
};
////! 処理中止キー
//const int KEYCODE_ESC = 0x1b;

//! 入力映像
cv::VideoCapture in_video;
//! 入力映像から取り出した画像
cv::Mat still_image;

void printext( void )
{
	for ( int i = 0; EXTENSIONS[i] != NULL; i++ )
	{
		printf("%s ", EXTENSIONS[i]);
	}
}

void printusage( void )
{
	printf("\n");
	printf("映像ファイルを連番をつけて静止画像に分解・保存します.\n");
	printf("10000枚ごとにフォルダを分けます.\n");
	printf("同名ファイルが存在していた場合,確認をとらずに上書きします.\n");
	printf("\n");
	printf("video2still.exe 入力ファイル 出力フォルダ 出力形式 [/nosplit]\n");
	printf("\n");
	printf("  出力フォルダ  mkdir を試みます.\n");
	printf("  出力形式      出力画像の拡張子です.\n");
	printf("                  ");
	printext();
	printf("\n");
	printf("  /nosplit      10000枚ごとのフォルダ分けをしません.\n");
	printf("\n");
}

void printargs(int argc, char *argv[] )
{
	printf("映像ファイル: %s\n", argv[1]);
	printf("出力フォルダ: %s\n", argv[2]);
	printf("出力形式    : %s\n", argv[3]);
}

/*!
@brief 画像出力の可否を拡張子から判別する.

@param[in] ext 拡張子
@return 対応しているときは true を返す.
対応していないときは false を返す.
*/
bool checkext(char *ext)
{
	for ( int i = 0; EXTENSIONS[i] != NULL; i++ )
	{
		if ( _stricmp( ext, EXTENSIONS[i]) == 0 )
		{
			return true;
		}
	}

	printf(__FUNCTION__": %s は未知の拡張子です.\n", ext);
	return false;
}

bool checkargs(int argc, char *argv[] )
{
	// パラメータ数
	if ( argc < 4 )
	{
		printf(__FUNCTION__": パラメータが不足しています.\n");
		printusage();
		return false;
	}
	// 出力フォルダ終端に \ があればつぶす
	for( ;; )
	{
		size_t last = strnlen( argv[2], BUFFERSIZE_FILENAME ) - 1;
		if ( argv[2][last] == '\\' )
		{
			argv[2][last] = NULL;
		}else{
			break;
		}
	}
	// 拡張子
	if ( checkext( argv[3] ) == false )
	{
		printusage();
		return false;
	}
	// 情報表示
	printargs( argc, argv );
	// オプションチェック
	if ( argc > 4 )
	{
		if ( _stricmp(OPTION_NOSPLIT, argv[4]) == 0 )
		{
			flag_nosplit = true;
			printf("フォルダ分け: なし\n");
		}
	}
	// 入力映像チェック
	if ( in_video.open( argv[1] ) == false )
	{
		printf(__FUNCTION__": 映像ファイルを利用できません.\n");
		return false;
	}
	// 出力フォルダチェック
	if ( _mkdir(argv[2]) == -1 )
	{
		if ( errno == EEXIST )
		{
			printf(__FUNCTION__": 出力フォルダはすでに作成されています.\n");
		}else{
			printf(__FUNCTION__": 出力フォルダを作成できません.\n");
			return false;
		}
	}

	return true;
}

int main(int argc, char *argv[])
{
	// パラメータチェック
	if ( checkargs(argc, argv) == false )
	{
		return 0;
	}

	//! 出力フォルダ名
	char outdir[BUFFERSIZE_FILENAME];
	if ( flag_nosplit == true )
	{
		sprintf_s(outdir, BUFFERSIZE_FILENAME-1, "%s", argv[2]);
	}
	//! 出力ファイル名
	char outstill[BUFFERSIZE_FILENAME];

	// メインループ
	bool flag_mainloop = true;
	for ( int dir = 0; flag_mainloop; dir++ )
	{
		// サブフォルダ作成
		if ( flag_nosplit == false )
		{
			// outdir を書き換える
			// フォルダ名は argv[2]\\0-10000
			sprintf_s(outdir, BUFFERSIZE_FILENAME-1, "%s\\%d-%d",
				argv[2], dir * OUTSTILL_UNIT, (dir+1) * OUTSTILL_UNIT);
			if ( _mkdir( outdir ) == -1 )
			{
				if ( errno != EEXIST )
				{
					printf("出力フォルダを作成できません.: %s\n", outdir);
				}
			}
		}
		// ファイル出力
		printf(__FUNCTION__": %d ...\n", dir*OUTSTILL_UNIT);
		for ( int i = 0; i < OUTSTILL_UNIT; i++ )
		{
			in_video >> still_image;
			if ( still_image.empty() == true )
			{
				flag_mainloop = false;
				break;
			}else{
				// ファイル名は outdir\\0.拡張子
				sprintf_s(outstill, BUFFERSIZE_FILENAME, "%s\\%d.%s",
					outdir, dir*OUTSTILL_UNIT + i, argv[3]);
				if ( strncmp(argv[3], "pgm", 3 ) == 0 )
				{
					cv::Mat gray( still_image.size(), CV_8UC1 );
					cv::cvtColor( still_image, gray, CV_RGB2GRAY );
					cv::imwrite( outstill, gray);
				}
				else
				{
					cv::imwrite( outstill, still_image);
				}
			}
		}
	}

	return 0;
}

更新履歴

2009年11月27日 14:51:56 連番を振る部分にバグがあったのを修正した.OUTSTILL_UNIT 枚出力するごとにメッセージを表示するよう変更した