概要
OpenCVで取り込んだMatデータを直接ピクセルごとに処理したくなる時があります。
今回はピクセル処理の基本の勉強としてMatデータに直接アクセスし、グレースケールへ変換する処理を行います。
バージョンはOpenCV3.2を使用しています。
コード
まずコードです。
今回はピクセルへのアクセスにdataを使用しています。
atを使用すると処理がかなり遅くなりましたので、dataでアクセスしています。(debug時の動作の未確認。Release時にどちらが早いかは確認していません。)
Mat RGB2Gray(Mat frame)
{
Mat gray = Mat::zeros(cv::Size(frame.cols, frame.rows), CV_8UC1);
int ch = frame.channels();
for (int i = 0; i < frame.rows; i++) {
for (int j = 0; j < frame.cols; j++) {
int num = frame.data[i * frame.step + j * ch + 0] * 0.299 +
frame.data[i * frame.step + j * ch + 1] * 0.587 +
frame.data[i * frame.step + j * ch + 2] * 0.114;
gray.data[i * gray.step + j] = num;
}
}
return gray;
}
atを使用する場合
for (int i = 0; i < row; i++) {
for (int j = 0; j < col; j++) {
int num = frame.at<Vec3b>(i,j)[0] * 0.299 +
frame.at<Vec3b>(i, j)[1] * 0.587 +
frame.at<Vec3b>(i, j)[2] * 0.114;
for (int k = 0; k < ch; k++) {
gray.at<unsigned char>(i, j) = num;
}
}
}
解説
Mat gray = Mat::zeros(cv::Size(frame.cols, frame.rows), CV_8UC1);
グレイスケールの画像を保存するMatデータを初期化しています。
サイズは取り込んだ画像、型はCV_8UC1(8bit,1channel)を指定しています。
※型に関してはコチラをどうぞ
・OpenCVの型情報の定数まとめ
http://d.hatena.ne.jp/arche_t/20090120/1232445728
for (int i = 0; i < frame.rows; i++) {
for (int j = 0; j < frame.cols; j++) {
}
}
画素ごとにラスタ捜査を行います。
int num = frame.data[i * frame.step + j * ch + 0] * 0.299 +
frame.data[i * frame.step + j * ch + 1] * 0.587 +
frame.data[i * frame.step + j * ch + 2] * 0.114;
引数の画像からRGBチャンネルを抜き出し、定数を掛け和を取っています。
値がそれぞれ違うのは、人間の目では青は弱く見え、緑が強く見えるからです。
frame.stepは行の画素数×チャンネル数です。
最後に足している0~2の値はチャンネルです。
3チャンネルの場合
RGBRGBRGB...
の順でデータが並んでいるため、チャンネルを考慮しなければいけません。
逆に1チャンネルの場合は1画素につき1チャンネルとなっている為
gray.data[i * gray.step + j]
のようにシンプルに表現することができます。
return gray;
最後に作成したグレースケール画像を返して終了です。
この処理では3チャンネルで入力した画像を1チャンネルで出力していることに気を付けてください。