cvSplit 使用例

opencv.jp での cvSplit

Split

マルチチャンネルの配列を,複数のシングルチャンネルの配列に分割する.または,配列から一つのチャンネルを取り出す.

void cvSplit( const CvArr* src, CvArr* dst0, CvArr* dst1,
              CvArr* dst2, CvArr* dst3 );
#define cvCvtPixToPlane cvSplit

src
    入力配列. 
dst0...dst3
    出力チャンネル.

関数cvSplitは,マルチチャンネルの配列をシングルチャンネルの配列に分割する.この操作には二つのモードがある.入力配列がNチャンネルの場合,先頭からN番目までの出力チャンネルが NULL でなければ,それらはすべて入力配列から取り出される.そうでなく,N個の出力チャンネルのうち一つだけが NULL でない場合は,この特定のチャンネルのみを抽出する.このいずれでもない場合はエラーとなる. N番目以降の出力チャンネルは常に NULL でなくてはならない. IplImageでは,画像から一つのシングルチャンネルを抽出するために,COIを伴うcvCopyも利用される.

opencv.jp - OpenCV-1.0:CXCORE 変形と置換(Transforms and Permutations)リファレンス マニュアル -

使用例概要

動画を読み込み,静止画を出力する.

入力動画 const char *IN_AVI_FILE[] main 関数で数値を入れ,ファイルを指定する
出力フォルダ const char *OUT_STILL_DIR[] OpenCV の仕様に従い BGR 順とする
出力画像形式 const char *OUT_STILL_FILENAME_TAIL BMPJPEG にしたいときに変更する

メモ

cvSplit の書き込み先はメモリ確保しておく必要がある.

  1. 出力フォルダを削除
  2. 出力フォルダを作成
  3. 主処理
    1. 動画から静止画を読み出す
    2. 静止画を色平面ごとに分割する
    3. 各色平面をファイル出力する

ソース

/*
 * 入力: AVI ファイル
 * 出力: PNG ファイル
 色平面ごとに分割して保存する
*/

#include "cv.h"
#include "cxcore.h"
#include "highgui.h"
#include <stdio.h>
#include <stdlib.h>

#pragma comment(lib, "cv.lib")
#pragma comment(lib, "cxcore.lib")
#pragma comment(lib, "highgui.lib")

// 入力ファイル
const char *IN_AVI_FILE[] = {
	"c:\\data\\video\\90frame.avi",
	"c:\\data\\video\\360frame.avi",
	"c:\\data\\video\\1858frame.avi",
};
// 出力フォルダ
const char *OUT_STILL_DIR[] = {
	"c:\\data\\image\\avi2rgbstill\\b\\",
	"c:\\data\\image\\avi2rgbstill\\g\\",
	"c:\\data\\image\\avi2rgbstill\\r\\",
};
// 出力ファイル名最大長
const int OUT_FILENAME_MAXLEN = 512;
// 出力画像拡張子
const char *OUT_STILL_FILENAME_TAIL = ".png";

// 出力フォルダを削除
//
//    /S      指定されたディレクトリに加えて、そのディレクトリ内のすべての
//            ディレクトリとファイルを削除します。ディレクトリ ツリーを削除
//            するときに使用します。
//
//    /Q      /S を指定してディレクトリ ツリーを削除するときに、確認の
//            メッセージを表示しません。(QUIET モード)
void deleteOutdir()
{
	char system_call[512];

	for ( int channel = 0; channel < 3; channel++ )
	{
		sprintf_s(system_call, 512,	"rmdir /s /q %s", OUT_STILL_DIR[channel]);
		system(system_call);
	}
}

// 出力フォルダを作成
void makeOutkdir()
{
	char system_call[512];

	for ( int channel = 0; channel < 3; channel++ )
	{
		sprintf_s(system_call, 512,	"mkdir %s", OUT_STILL_DIR[channel]);
		system(system_call);
	}
}

// BGR 各平面の画像保存
void saveStill( IplImage **img_planes )
{
	static int img_counter = 0;
	static char out_still_filename[OUT_FILENAME_MAXLEN];
	
	for ( int channel = 0; channel < 3; channel++ )
	{
		sprintf_s(out_still_filename, OUT_FILENAME_MAXLEN,
			"%s%d%s", OUT_STILL_DIR[channel], img_counter, OUT_STILL_FILENAME_TAIL);
		cvSaveImage(out_still_filename, img_planes[channel]);
	}
	img_counter++;
}

// BGR 各平面の画像メモリ確保.解放はプログラム終端で手書きすること
void planesInit( CvCapture *capture, IplImage **img_planes)
{
	int width = (int)cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH);
	int height = (int)cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT);

	for ( int channel = 0; channel < 3; channel++ )
	{
		img_planes[channel] = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1);
	}
}

int main(int argc, char **argv)
{
	CvCapture *capture = cvCaptureFromAVI(IN_AVI_FILE[1]);
	IplImage *img_query;
	IplImage *img_planes[3] = { NULL, NULL, NULL, };

	deleteOutdir();
	makeOutkdir();
	planesInit(capture, img_planes);

	while( img_query = cvQueryFrame(capture) )
	{
		cvSplit(img_query, img_planes[0], img_planes[1], img_planes[2], NULL);
		saveStill(img_planes);
	}

	cvReleaseImage(&img_planes[0]);
	cvReleaseImage(&img_planes[1]);
	cvReleaseImage(&img_planes[2]);
	cvReleaseCapture(&capture);

	return 0;
}