Miyabiarts.net

一年に一度の更新頻度

OpenCVでの画素へのアクセス方法

tsunotterで、

「OpenCVで任意のピクセルの画素値に直接どうやってアクセスする? #opencv」

という質問があったので、私のOpenCVでの画素へのアクセス方法を書いておきます。

私は、基本的にOpenCVはC++インタフェースを使っているので、画像はcv::Mat_で扱っています。
画素へのアクセスは、以下の2つの方法を使い分けており、普段は1つ目で、処理を速くしたい場合は2つ目の方法を用いています。
サンプルコードでは、400×400のRGB画像の全画素を赤くするもので、やっていることはcv::Fillと同じです。

任意の画素へのアクセス

単純にcv::Mat_::operator()( y, x )を用いて、画素にアクセスする手法です。
xとyが逆にならないように気をつけてください。
また、cols=width、rows=heightとなっています。

#include <opencv2/opencv.hpp>

int main()
{
  // 400x400 RGB画像を作成
  cv::Mat_<cv::Vec3b> img( cvCreateImage( cvSize( 400, 400 ), IPL_DEPTH_8U, 3 ) );

  // 全画素を赤くする
  for( int y = 0 ; y < img.rows ; ++y )
    {
      for( int x = 0 ; x < img.cols ; ++x )
	{
          // 画素へアクセス
	  img( y, x )[ 0 ] = 0;
	  img( y, x )[ 1 ] = 0;
	  img( y, x )[ 2 ] = 0xff;
	}
    }
  // 画像出力
  cv::imwrite( "result.bmp", img );
  return 0;
}

当然ですが、cv::Vec3bをunsigned charに変えることで、グレースケール画像も扱えます。

任意の画素へのアクセス(高速版)

1つ目の方法だと、1つの画素にアクセスするたびにcv::Mat_::operator ( y, x )を呼び出すオーバヘッドがかかるため、ポインタ操作でなるべくオーバヘッドを減らす方法です。
スキャンラインで画像を走査する際に、スキャンラインの先頭画素のポインタを取得した上で、後はポインタのインクリメンタルによりアクセスする画素を進めます。
気をつけることは、ポインタを進めすぎるとバッファ・オーバランが起こるので、アクセス範囲には十分気をつけてください。

#include <opencv2/opencv.hpp>;

int main()
{
  // 400x400 RGB画像を作成
  cv::Mat_<cv::Vec3> img( cvCreateImage( cvSize( 400, 400 ), IPL_DEPTH_8U, 3 ) );

  // 全画素を赤くする
  for( int y = 0 ; y < img.rows ; ++y )
    {
      // 先頭の画素のポインタを取得
      cv::Vec3b *p = &img( y, 0 );
      for( int x = 0 ; x < img.cols ; ++x )
	{
           // 画素へアクセス
	  ( *p )[ 0 ] = 0;
	  ( *p )[ 1 ] = 0;
	  ( *p )[ 2 ] = 0xff;
     // 次の画素へ進める
	  p++;
	}
    }
  // 画像出力
  cv::imwrite( "result.bmp", img );
  return 0;
}

cv::Vec3bをunsigned charに変えることで、グレースケール画像も扱えます。
このとき、画素へのアクセスに用いるポインタは型情報も持っているため、ポインタのインクリメンタルで画素単位で進めることができ、1画素が何バイトで構成されているかを意識しないで良いので楽ですし、間違いが少なくなります。

他にもやり方は色々ありますが、私は以上の方法で画素にアクセスすることが多いです。

広告

OpenCVでの画素へのアクセス方法」への1件のフィードバック

  1. ピンバック:Tweets that mention OpenCVでの画素へのアクセス方法 | Miyabiarts.net -- Topsy.com

%d人のブロガーが「いいね」をつけました。