読者です 読者をやめる 読者になる 読者になる

OpenCV2.x系で画像を読み込んでcv::Matに格納し、情報を得る


このエントリーをはてなブックマークに追加

OpenCV2.x系から画像をcv::Matで扱うようになったのに未だに慣れず、毎回調べてしまっている。このへんでいい加減まとめておく。
1 cv::Matの基本処理 — OpenCV2 プログラミングブック リファレンス編がもっとも参考になった。以下はこのサンプルをもとにしている。

環境

OpenCV 2.4.3 + Visual Studio 2012

コード

OpenCVのサンプルに付属していた画像(横800 x 縦600のカラーpng)を読み込み、各種値を出力。

#include "stdafx.h"
#include <iostream>
#include <opencv2/highgui/highgui.hpp>

#ifdef _DEBUG
#pragma comment(lib, "opencv_core243d")
#pragma comment(lib, "opencv_highgui243d")
#else
#pragma comment(lib, "opencv_core243")
#pragma comment(lib, "opencv_highgui243")
#endif


using namespace std;

int _tmain(int argc, _TCHAR *argv[])
{
	cv::Mat img = cv::imread("./input/puzzle.png");
	if (img.empty()){
		cout << "couldn't read the image." << endl;
		return 1;
	}

	// http://book.mycom.co.jp/support/pc/opencv2/c3/opencv_mat.html#mat-various-properties

	// 行数
	std::cout << "rows: " << img.rows <<std::endl;
	// 列数
	std::cout << "cols: " << img.cols << std::endl;


	// 次元数(画像なので縦・横の2次元)
	std::cout << "dims: " << img.dims << std::endl;
	// サイズ(2次元の場合)
	std::cout << "size[]: " << img.size().width << "," << img.size().height << std::endl;
	// ビット深度ID
	std::cout << "depth (ID): " << img.depth() << "(=" << CV_8U << ")" << std::endl;
	// チャンネル数
	std::cout << "channels: " << img.channels() << std::endl;
	// (複数チャンネルから成る)1要素のサイズ [バイト単位]
	std::cout << "elemSize: " << img.elemSize() << "[byte]" << std::endl;
	// 1要素内の1チャンネル分のサイズ [バイト単位]
	std::cout << "elemSize1 (elemSize/channels): " << img.elemSize1() << "[byte]" << std::endl;
	// タイプ
	std::cout << "type (ID): " << img.type() << "(=" << CV_8UC3 << ")" << std::endl;
	// 要素の総数
	std::cout << "total: " << img.total() << std::endl;
	// ステップ数 [バイト単位]
	std::cout << "step: " << img.step << "[byte]" << std::endl;
	// 1ステップ内のチャンネル総数
	std::cout << "step1 (step/elemSize1): " << img.step1()  << std::endl;
	// データは連続か?
	std::cout << "isContinuous: " << (img.isContinuous()?"true": "false") << std::endl;
	// 部分行列か?
	std::cout << "isSubmatrix: " << (img.isSubmatrix()?"true": "false") << std::endl;
	// データは空か?
	std::cout << "empty: " << (img.empty()?"true": "false") << std::endl;

	return 0;
}

直接Public変数を見るものとメソッドを呼び出すものとが混在していてややこしい。

出力結果は以下。

rows: 600
cols: 800
dims: 2
size[]: 800,600
depth (ID): 0(=0)
channels: 3
elemSize: 3[byte]
elemSize1 (elemSize/channels): 1[byte]
type (ID): 16(=16)
total: 480000
step: 2400[byte]
step1 (step/elemSize1): 2400
isContinuous: true
isSubmatrix: false
empty: false

特によく使いそうなのは

  • img.cols (横幅)
  • img.rows (縦幅)
  • img.channels() (1ピクセルあたりの色数。普通のカラー画像だとR, G, Bで3、白黒画像だと1)
  • img.elemSize() (1ピクセルあたりが使うバイト数)
  • img.step (ステップ数。ピクセルを走査するときに使う)

あたりだろうか。

注意すべきはimg.depth()とimg.type()。これらのメソッドによって呼び出されるのは、types_c.hに定義されているIDである。例えばimg.depth()によって得られる0は、types_c.hを見るとCV_8Uに等しい。これにより1チャネルは8bitのunsignedから構成されていることがわかる。同様にimg.type()によって得られる16はCV_8UC3に等しい。これにより1ピクセルは8bitのunsignedの3チャネル分から構成されていることがわかる。