第5回 初めてのOpenCV開発 ― coreモジュール【OpenCV 3.1.0】:OpenCV入門【3.0対応】(1/2 ページ)
OpenCVのcoreモジュールの概要を解説。そのMatクラスを使って画像データを扱う方法や、ユーティリティ関数、OpenCV 3.0より導入されたUMatクラスを紹介する。
ご注意:本記事は、@IT/Deep Insider編集部(デジタルアドバンテージ社)が「www.buildinsider.net」というサイトから、内容を改変することなく、そのまま「@IT」へと転載したものです。このため用字用語の統一ルールなどは@ITのそれとは一致しません。あらかじめご了承ください。
1. はじめに
前回、OpenCVを使ったアプリケーションのプロジェクト作成方法について解説を行いました。今回はOpenCVのcoreモジュールについて解説します。
以下の表に、今回紹介するcoreモジュールの機能の概要をまとめました。
モジュール名 | 機能の概要 |
---|---|
core | 画像・行列データ構造の提供、配列操作、XMLおよびYAML入出力、コマンドラインパーサー、ユーティリティ機能など |
モジュール(core)の概要 |
また、筆者が確認した環境は以下の通りです。
項目 | 内容 |
---|---|
OpenCVバージョン | OpenCV 3.1.0 |
Visual Studio | Visual Studio 2013 Update5 |
ビルド構成 | x64Release |
OS | Windows 10 Pro(64bit) |
筆者が確認した環境 |
2. Matクラス
OpenCVでは画像データを格納するデータ構造としてMatクラスを提供しています。OpenCVの多くの関数の入出力は、Matクラスを介して行われます。そのため、このMatクラスを取り扱うに当たり、以下の3つの基本的な処理の方法について、例を用いながら解説します。
- インスタンス生成
- プロパティ取得
- ピクセルへのアクセス
2.1 インスタンス生成
ここではMatクラスのインスタンス生成方法について解説します。画像ファイルを読み込んでインスタンスを生成する方法もありますが、その方法については次回(imgcodecsモジュール)の記事で紹介します。
そこで、画像の幅320px、高さ240px、赤色の画像データ生成を行う下記のコードを例に用いながら、インスタンス生成方法を解説します。
cv::Mat img(cv::Size(320, 240), CV_8UC3, cv::Scalar(0, 0, 255));
上記コードでポイントとなる項目と意味は以下の通りです。
項目 | 意味 |
---|---|
cv::Size(320, 240) | 画像サイズ(幅320px、高さ240px) |
CV_8UC3 | ビット深度=符号なしの8bit整数、チャンネル数=3 |
cv::Scalar(0, 0, 255) | 画像の色。この例では赤色(B=0、G=0、R=255) |
上記コードのポイントと意味 |
以降は、画像のプロパティを指定するために用いる、
- ビット深度・チャンネル数
- cv::Size
- cv::Scalar
についてもう少し詳しく説明を行います。
2.1.1 ビット深度・チャンネル数
OpenCVでは、
CV_<ビット深度>{U|S|F}C<チャンネル数>
※Uは符号なし、Sは符号付き、Fは浮動小数点数を表す
という表記によって画像のビット深度とチャンネル数を表現しています。
そのため、前述のコードにある、
CV_8UC3
は、
- ビット深度=符号なしの8bit整数
- チャンネル数=3
という意味を表しています。
2.1.2 cv::Size
OpenCVでは、cv::Sizeというデータ構造を使うことで画像のサイズを指定できます。cv::Sizeを使う場合、第1引数がwidth(画像の幅)、第2引数がheight(画像の高さ)となります。
そのため、前述のコードにある、
cv::Size(320, 240)
は画像サイズ(幅320px、高さ240px)という意味を表しています。
2.1.3 cv::Scalar
OpenCVでは、cv::Scalarというデータ構造を使うことで画像の色を指定できます。ただしOpenCVの画像データは、RGB表色系の場合、cv::Scalarに対してB、G、Rの順に指定する点に注意ください。
そのため、前述のコードにある、
cv::Scalar(0, 0, 255)
は、赤色(R=255、G=0、B=0)という意味を表しています。
2.2 プロパティ取得
Matクラスのメソッドを呼ぶことで画像データの各種プロパティを取得できます。以降、各種プロパティを取得するメソッドについて例を用いながら紹介します。
2.2.1 rows、cols
Matクラスは画像データだけでなく、行列も取り扱うことができます。このことからMatクラスには、行列の行数を参照するrows、列数を参照するcolsが、メンバー変数として定義されています。
Matクラスのメンバー変数rows/colsを参照することで、画像の高さ/幅を取得できます。
- cols: 画像の幅(※行列の列数に対応)
- rows: 画像の高さ(※行列の行数に対応)
以下に画像の幅と高さを取得するサンプルコードを示します。
#include <opencv2/core.hpp>
#include <iostream>
int main(int argc, const char* argv[])
{
// 幅320px、高さ240px、3チャンネルのインスタンスを生成する
cv::Mat img(cv::Size(320, 240), CV_8UC3, cv::Scalar(0, 0, 255));
// 画像の幅を表示する
std::cout << "width: " << img.cols << std::endl;
// 画像の高さを表示する
std::cout << "height: " << img.rows << std::endl;
return 0;
}
このサンプルコードを実行したときの標準出力は以下の通りです。この例では、imgは幅320px、高さ240pxなので以下のような標準出力が行われます。
width: 320
height: 240
2.2.2 channelsメソッド
Matクラスのchannelsメソッドにより画像のチャンネル数を取得できます。グレースケール画像の場合は「1」、カラー画像の場合は「3」、アルファチャンネル付きのカラー画像の場合は「4」が返ってきます。
以下に画像のチャンネル数を取得するサンプルコードを示します。
#include <opencv2/core.hpp>
#include <iostream>
int main(int argc, const char* argv[])
{
// 幅320px、高さ240px、3チャンネルのインスタンスを生成する
cv::Mat img(cv::Size(320, 240), CV_8UC3, cv::Scalar(0, 0, 255));
// チャンネル数を表示する
std::cout << "channels: " << img.channels() << std::endl;
return 0;
}
このサンプルコードを実行したときの標準出力は以下の通りです。この例では、imgは3チャンネルなので以下のような標準出力が行われます。
channels: 3
2.2.3 depthメソッド
Matクラスのdepthメソッドにより、画像のビット深度を取得できます。ただし、depthメソッドの戻り値はビット深度の値そのものではなく、OpenCV内に定義される定数値である点に注意してください。
以下にinclude\opencv2\core\cvdef.hファイルで定義される定数の定義部を引用します。
#define CV_8U 0
#define CV_8S 1
#define CV_16U 2
#define CV_16S 3
#define CV_32S 4
#define CV_32F 5
#define CV_64F 6
また、OpenCV内に定義されるビット深度名とそれらの意味は以下の通りです。
ビット深度名 | 意味 |
---|---|
CV_8U | 符号なしの8bit整数( 0((〜))255 ) |
CV_8S | 符号付きの8bit整数( -128((〜))127 ) |
CV_16U | 符号なしの16bit整数( 0((〜))65535 ) |
CV_16S | 符号付きの16bit整数( -32768((〜))32767 ) |
CV_32S | 符号付きの32bit整数( -2147483648((〜))2147483647 ) |
CV_32F | 32bit浮動小数点数 ( -FLT_MAX..FLT_MAX, INF, NAN ) |
CV_64F | 64bit浮動小数点数( -DBL_MAX..DBL_MAX, INF, NAN ) |
OpenCV内に定義されるビット深度名と意味 |
以下に画像のビット深度を取得するサンプルコードを示します。
#include <opencv2/core.hpp>
#include <iostream>
// ビット深度名を表示する自作関数
void printDepth(cv::Mat& img)
{
// 画像のビット深度を取得する
unsigned int depth = img.depth();
std::string strDepth =
(
depth == CV_8U ? "CV_8U" :
depth == CV_8S ? "CV_8S" :
depth == CV_16U ? "CV_16U" :
depth == CV_16S ? "CV_16S" :
depth == CV_32S ? "CV_32S" :
depth == CV_32F ? "CV_32F" :
depth == CV_64F ? "CV_64F" :
"Other"
);
std::cout << "depth: " << strDepth << std::endl;
}
int main(int argc, const char* argv[])
{
// 幅320px、高さ240px、3チャンネルのインスタンスを生成する
cv::Mat img(cv::Size(320, 240), CV_8UC3, cv::Scalar(0, 0, 255));
// ビット深度名を表示する自作関数
printDepth(img);
return 0;
}
このサンプルコードを実行したときの標準出力は以下の通りです。この例では、imgのビット深度は符号なしの8bit整数であるため、以下のような標準出力が行われます。
depth: CV_8U
2.3 ピクセルへのアクセス
ここでは任意のピクセルの画素値にアクセスする方法の1つであるatメソッドについて紹介します。その他のアクセス方法については、
を参考ください。
2.3.1 画素値の参照
Matクラスのatメソッドを以下のように呼び出すことで、変数imgにおける座標(x, y)の画素値を参照できます。ただし、このときatメソッドに渡すパラメーターは(y, x)の順に指定する必要がある点に注意が必要です。
img.at<cv::vec3b>(y, x);
以下に画素値を参照するサンプルコードを示します。
#include <opencv2/core.hpp>
#include <iostream>
int main(int argc, const char* argv[])
{
// 幅320px、高さ240px、3チャンネルのインスタンスを生成する
cv::Mat img(cv::Size(320, 240), CV_8UC3, cv::Scalar(0, 0, 255));
// (1)座標(0, 100)の画素値を取得する
// ※atに渡すパラメーターは(y, x)の順である点に注意
// ※Matのデータは(RGB表色系の場合)BGRの順に並んでいる点に注意
cv::Vec3b intensity = img.at<cv::Vec3b>(100, 0);
uchar blue = intensity.val[0];
uchar green = intensity.val[1];
uchar red = intensity.val[2];
// (2)画素値を表示する
std::cout << "R: " << (unsigned int)red << std::endl;
std::cout << "G: " << (unsigned int)green << std::endl;
std::cout << "B: " << (unsigned int)blue << std::endl;
return 0;
}
このサンプルコードを実行したときの標準出力は以下の通りです。この例では、img(全てのピクセルが赤色の画像)における座標(0, 100)の画素値は赤色であるため、以下のような標準出力が行われます。
R: 255
G: 0
B: 0
2.3.2 画素値の変更
atメソッドを以下のように呼び出すことで、変数imgにおける座標(x, y)の画素値を変更できます。また、このときatメソッドに渡すパラメーターは(y, x)の順序である点と、Matのデータは(RGB表色系の場合)BGRの順に並んでいる点に注意が必要です(※redValue、greenValue、blueValueは変更したい画素値)。
img.at<cv::vec3b>(y, x)[0] = blueValue;
img.at<cv::vec3b>(y, x)[1] = greenValue;
img.at<cv::vec3b>(y, x)[2] = redValue;
以下に画素値を変更するサンプルコードを示します。
#include <opencv2/core.hpp>
#include <iostream>
int main(int argc, const char* argv[])
{
// 幅320px、高さ240px、3チャンネルのインスタンスを生成する
cv::Mat img(cv::Size(320, 240), CV_8UC3, cv::Scalar(0, 0, 255));
// (1)座標(0, 100)の画素値を変更する
// ※atに渡すパラメーターは(y, x)の順である点に注意
// ※Matのデータは(RGB表色系の場合)BGRの順に並んでいる点に注意
img.at<cv::Vec3b>(100, 0)[0] = 255;
img.at<cv::Vec3b>(100, 0)[1] = 0;
img.at<cv::Vec3b>(100, 0)[2] = 0;
// (2)座標(0, 100)の画素値を取得する
cv::Vec3b intensity = img.at<cv::Vec3b>(100, 0);
uchar blue = intensity.val[0];
uchar green = intensity.val[1];
uchar red = intensity.val[2];
// (3)画素値を表示する
std::cout << "R: " << (unsigned int)red << std::endl;
std::cout << "G: " << (unsigned int)green << std::endl;
std::cout << "B: " << (unsigned int)blue << std::endl;
return 0;
}
このサンプルコードを実行したときの標準出力は以下の通りです。この例では、(1)の処理で座標(0, 100)の画素値は青色(R=0、G=0、B=255)に変更しているため、以下のような標準出力が行われます。
R: 0
G: 0
B: 255
Copyright© Digital Advantage Corp. All Rights Reserved.