2010/04/13

ピクセル単位での操作

前回までは、画像全体に対して同一の操作を行ってきました。
今度は、1ピクセルごとにデータをいじりたいと思います。

というわけで今回のお題は色相関。
↓こんなの









横幅360ピクセルの画像を生成して、
1ピクセルごとに青、緑、赤の値を変化させていっています。

関数を使ったものと、ポインタで直接値を変更したものを作ってみました。


//色相関みたいなものを作る
#include "cv.h"
#include "highgui.h"
 double g_cvSet2DTime;
 double g_PointerTime;

void  SetScalarToPixcel(IplImage* img,int x, int setblue, int setgreen, int setred);
void  SetScalarToPixcel_PointVer(IplImage* img,int x, int setblue, int setgreen, int setred);



int main( int argc, char** argv )
{
 //表示用のウィンドウを作る
 cvNamedWindow("Gradation",CV_WINDOW_AUTOSIZE);
 cvNamedWindow("Gradation2",CV_WINDOW_AUTOSIZE);

 g_cvSet2DTime=0.0;
 g_PointerTime=0.0;
 //空っぽのイメージを作成
 IplImage * colorMap=cvCreateImage(cvSize(360,40),IPL_DEPTH_8U,3); //IPL_DEPTH_8U 符号なし8ビット整数
 IplImage * colorMapPointer=cvCreateImage(cvSize(360,40),IPL_DEPTH_8U,3);

 //初期化(真っ黒になる)
 cvZero(colorMap);
 cvZero(colorMapPointer);
 

 //WikiPediaに色相関を作る方法が載っていたのでそれを参考に作成します。
 //                青     緑     赤
 //  0°- 60°   0固定       0から255へ  255固定
    // 60°-120°   0固定       255固定     255から0へ
 //120°-180°   0から255へ  255固定     0固定
 //180°-240°   255固定     255から0へ  0固定
 //240°-300°   255固定     0固定       0から255へ
 //300°-360°   255から0へ  0固定       255固定
 //
 int modular=0;
 int addvalue=0;
 for(int degree=1;degree<=360;degree++)
 { 
  modular=(degree)%60;
  
  if(degree==60)
  {
   SetScalarToPixcel(colorMap,degree,0,255,255);
   SetScalarToPixcel_PointVer(colorMapPointer,degree,0,255,255);
  }
  if(degree==120)
  {
   SetScalarToPixcel(colorMap,degree,0,255,0);
   SetScalarToPixcel_PointVer(colorMapPointer,degree,0,255,0);
  }
  if(degree==180)
  {
   SetScalarToPixcel(colorMap,degree,255,255,0);
   SetScalarToPixcel_PointVer(colorMapPointer,degree,255,255,0);
  }
  if(degree==240)
  {
   SetScalarToPixcel(colorMap,degree,255,0,0);
   SetScalarToPixcel_PointVer(colorMapPointer,degree,255,0,0);
  }
  if(degree==300)
  {
   SetScalarToPixcel(colorMap,degree,255,0,255);
   SetScalarToPixcel_PointVer(colorMapPointer,degree,255,0,255);
  }
  if(degree==360)
  {
   SetScalarToPixcel(colorMap,degree,0,0,255);
   SetScalarToPixcel_PointVer(colorMapPointer,degree,0,0,255);
  }

  if(  0<=degree && degree< 60)
  { 
   addvalue=modular*4;
   SetScalarToPixcel(colorMap,degree,0,addvalue,255);
   SetScalarToPixcel_PointVer(colorMapPointer,degree,0,addvalue,255);
  }
  if( 60<degree && degree<120)
  { 
   addvalue=255-modular*4;
   SetScalarToPixcel(colorMap,degree,0,255,addvalue);
   SetScalarToPixcel_PointVer(colorMapPointer,degree,0,255,addvalue);
  }
  if(120<degree && degree<180)
  { 
   addvalue=modular*4;
   SetScalarToPixcel(colorMap,degree,addvalue,255,0);
   SetScalarToPixcel_PointVer(colorMapPointer,degree,addvalue,255,0);
  }

  if(180<degree && degree<240)
  { 
   addvalue=255-modular*4;
   SetScalarToPixcel(colorMap,degree,255,addvalue,0);
   SetScalarToPixcel_PointVer(colorMapPointer,degree,255,addvalue,0);
  }
  if(240<degree && degree<300)
  { 
   addvalue=modular*4;
   SetScalarToPixcel(colorMap,degree,255,0,addvalue);
   SetScalarToPixcel_PointVer(colorMapPointer,degree,255,0,addvalue);
  }
  if(300<degree && degree<360)
  { 
   addvalue=255-modular*4;
   SetScalarToPixcel(colorMap,degree,addvalue,0,255);
   SetScalarToPixcel_PointVer(colorMapPointer,degree,addvalue,0,255);
  }

  
 }
 cvShowImage("Gradation",colorMap);
 cvShowImage("Gradation2",colorMapPointer);

 printf( "execution time(cvSet2D) = %g ms\n", g_cvSet2DTime/((double)cvGetTickFrequency()*1000.) );
 printf( "execution time(Pointer) = %g ms\n", g_PointerTime/((double)cvGetTickFrequency()*1000.) );
 //5秒間表示
 cvWaitKey(5000);

 //リソースの開放
 cvReleaseImage(&colorMap);
 cvReleaseImage(&colorMapPointer);
 cvDestroyWindow("Gradation");
 cvDestroyWindow("Gradation2");
}

void  SetScalarToPixcel(IplImage* img,int x, int setblue, int setgreen, int setred)
{
 double t = 0;
    t = (double)cvGetTickCount();
   
  for(int y=0;y<img->height;y++)
  {
   //インデックスがheight,widthの順で並んでるので注意
   cvSet2D(
    img,
    y,
    x-1,
    cvScalar(setblue,setgreen,setred)
    );
  }
 t = (double)cvGetTickCount() - t;
    g_cvSet2DTime=g_cvSet2DTime+t; 
}
void  SetScalarToPixcel_PointVer(IplImage* img,int x, int setblue, int setgreen, int setred)
{
 double t = 0;
    t = (double)cvGetTickCount();
   
  for(int y=0;y<img->height;y++)
  {
   uchar* ptr=(uchar*)(img->imageData + y *img->widthStep);

    ptr[3*x+0]=setblue;
    ptr[3*x+1]=setgreen;
    ptr[3*x+2]=setred;
   
  }
 t = (double)cvGetTickCount() - t;
    
 g_PointerTime=g_PointerTime+t;
}


関数を使った場合と、ポインタで直接いじった場合の差は以下のようになりました。
execution time(cvSet2D) = 3.85831 ms
execution time(Pointer) = 0.969397 ms

関数を使うと、オーバーヘッドはどうしても出てしまいますね。。。

0 件のコメント:

コメントを投稿