ページ 11

Handleへの高速書き込みをしたいのですが。

Posted: 2012年11月21日(水) 11:08
by yoshihingis
お世話になります。
C言語初心者です。

以前、ここの掲示板で質問をして、おかげさまで読み込んだRawデータをDirectXで表示することが出来ました。
下記のコードはその改良版で、NoiseTest0000.raw-NoiseTest5954.rawというRGB 8bitX3の連番カラー静止画を読み込んで、Vsyncに同期して表示するプログラムです。
SSD上に、静止画ファイルを置いておけば、データ読み込みは3msec程度で済むので、連番静止画を動画の様に見せることが出来てます。


(1)行いたいこと。下記のDrawPixelSoftImageで描画データをhandleに書き込んでいますが、この部分を高速化したいと思ってます。
  別にDrawPixelSoftImageを使わなくても良いので、他に好適な別関数があれば教えて頂けませんでしょうか。

// Image Write
DrawPixelSoftImage( handle0, x, y + y_offset , in[y*inwidth*3 + x*3], in[y*inwidth*3 + x*3+1], in[y*inwidth*3 + x*3 +2], 255 ) ;

(2)高速化したい理由
 今は720X480 8x3chの画像ですが、もっと大きな画像を描画しようとしたとき、このhandle0へのデータ書き込みだけで、OpenMPで並列化しても、22msec程度かかかります。
 30FPS位(33msec)で表示したいので、この部分だけで22msecかかると、CPUで何か画像処理をさせる時間が短くなり、たいした処理が出来なくなります。

(3)その他の要望
 今は8bitX3CHのカラー画像ですが、8bitx1CHのグレースケール画像を表示させることも考えています。
 DrawPixelSoftImageだとグレースケールの場合、RGBに同一データを書き込むことになりますが、これだとグレースケール8bitX1CHなのに、3CH分を書き込まねばならず書き込み時間を損することになります。
 グレースケール画像を効率的にhandleに渡す方法は有りませんでしょうか?

 どなたか、良い方法をご存知でしたら、ご教授頂ければ幸いです。

コード:

#include "DxLib.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <omp.h>


int WindowWidth = 1680;
int WindowHeight = 1050;

int LOOP;
int START = 0;
int END   = 5954;


int inwidth = 720;
int inheight = 480;

int y_offset = 50;

int Color;

int outwidth = 0;
int outheight =0;

int x,y,i,j,cno,xx=0;

int StartTime0,EndTime0,EndTime1,EndTime2;

//画像入出力イメージ
char *in;



int thread_num = 4;

char ch1[512],ch2[512] ;
char c_zero[5] = "0000";
char no[10];


FILE *fp1;


int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )
{
	int handle0, grhandle0 ;



//LCD表示初期設定

   SetScreenMemToVramFlag( TRUE ) ;


	// DXライブラリの初期化
	if( DxLib_Init() < 0 ) return -1;

	//描画Windowsのサイズ設定
	SetGraphMode( WindowWidth , WindowHeight , 32 ) ;

	ChangeWindowMode(TRUE); // ウィンドウモードに設定

	SetDrawScreen( DX_SCREEN_BACK ); //描画先を表画面に設定


    in =(char* )malloc(inwidth*inheight*3);


for(LOOP = START;LOOP <= END;LOOP++){


//入力画像データFILE名作成

	//Input_image Read from FILE

    sprintf(no,"%d",LOOP);
	cno = (int)(strlen(no));
	strcpy(ch1,"");
    strcpy(ch1,"NoiseTest");
	strncat(ch1,c_zero,4 -cno);
	strcat(ch1,no);
	strcat(ch1,".raw");

	printf("INPUT FILE NAME:%s\n",ch1);


//Buffer確保

	//Input_image Read from FILE

	StartTime0 = GetNowCount() ;

   fp1 = fopen(ch1,"rb");
   if(fp1 == NULL){
	   printf("Input FILE Error!!\n");
	   getchar();
	   return -1;
   }
   	  
	    fread(in,sizeof(char),inwidth*inheight*3,fp1);
		fclose(fp1);
	
	EndTime0 = GetNowCount() ;
	

     


//*************
//初期画面表示
//*************
	 	 
	ClearDrawScreen();//ScreenのClear

	// 白色の値を取得
	Color = GetColor( 255 , 255 , 255 ) ;


	EndTime1 = GetNowCount() ;

			
	// 空のフルカラー画像を作成する
	handle0 = MakeARGB8ColorSoftImage(inwidth+50,inheight+50) ;

//Thread数の設定
omp_set_num_threads(4);


#pragma omp parallel for private(x), firstprivate(y_offset,inwidth)

	/* 入力データを画面表示メモリにSetする。*/
	for( y = 0; y < inheight; y ++ )
	{
		for( x = 0; x < inwidth; x ++ )
		{
						
			// Image Write
			DrawPixelSoftImage( handle0, x, y + y_offset , in[y*inwidth*3 + x*3], in[y*inwidth*3 + x*3+1], in[y*inwidth*3 + x*3 +2], 255 ) ;

		
		}
	}

  
	// グラフィックハンドルを作成
	grhandle0 = CreateGraphFromSoftImage( handle0 ) ;


	// 使い終わったら解放
	DeleteSoftImage( handle0 ) ;
	

	// グラフィックハンドルを描画
	 DrawGraph( 0, 0, grhandle0,  TRUE ) ;

	 EndTime2 = GetNowCount() ;

	 Color = GetColor( 255 , 255 , 255 ) ;

	 DrawFormatString( 20, 650, Color, "Read Input Image Time:%d[msec]\n",EndTime0-StartTime0 ) ;
	 DrawFormatString( 20, 680, Color,"DirectX Process Time:%d[msec]\n",EndTime2-EndTime1 ) ;

	//LCD Vsync 2Wait(30FPS)
	WaitVSync( 2 ) ;

	ScreenFlip(); //裏画面を表画面に反映

	//メモリ読み込んだ画像を消去する。
	//これを入れないと、多数の静止画を読み込んだ時、メモリが更新されなくなる。
	InitGraph() ;

	}

   //Memory Release
   free(in);
	

	// キー入力待ち
	WaitKey();
	

	// DXライブラリの後始末
	DxLib_End();

	// ソフトの終了
	return 0;
}

Re: Handleへの高速書き込みをしたいのですが。

Posted: 2012年11月21日(水) 11:52
by softya(ソフト屋)
とりあえず下記の方法を試してみてください。
「SoftImageに対する単色の書き込み」
http://hpcgi2.nifty.com/natupaji/bbs/pa ... st&no=1641
これを応用すれば(1)(3)の速度的な問題は大幅に軽減するはずです。

Re: Handleへの高速書き込みをしたいのですが。

Posted: 2012年11月21日(水) 15:28
by yoshihingis
softya様
 早速のご回答ありがとうございました。
 「SoftImageに対する単色の書き込み」を参考にして、コード変更したところ、720X480の8bitX3のカラー画像の書き込みは2msec程度の処理時間となりました。
 どうもありがとうございました。

Re: Handleへの高速書き込みをしたいのですが。

Posted: 2012年11月28日(水) 10:36
by yoshihingis
 C言語初心者です。以前にHandleへのデータの高速書き込みの質問をさせて頂き、下記のようなコードにより高速化ができました。

★コードの目的:NoiseTEst00000.raw-NoiseTest5954.raw 1000x666pixels 8bit 1ch gray sacleの連番静止画を読み込み、LCDのリフレッシュレートで同期させて表示し、動画に見せる。

★行いたいこと:αブレンディングのデータ無しでBGRの3CHデータを書き込んでいるが、gray scaleなので、1CHにすることはできないか?

int SetCreateDrawValidGraphChannelNum( int ChannelNum ) ;で描画のチャネル数を1CHに指定できるようなのですが、この場合、MakeScrennで描画グラフィックを作成しますが、この場合、「GetImageAddressSoftImage」は使用できなくなると思います。
 何かうまい手法が有りましたら、ご教授願いたいのですが。

 よろしくお願いいたします。


コード:

#include "DxLib.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <omp.h>


int WindowWidth = 1600;
int WindowHeight = 1200;

int LOOP;
int START = 0;
int END   = 5954;

int inwidth = 1000;
int inheight = 666;


int Color;

int outwidth = 0;
int outheight =0;

int x,y,i,j,cno,xx=0;

int pBufferSize = 0;

int StartTime0,EndTime0;

BYTE *image;

char *in;

int thread_num = 4;

char ch1[512],ch2[512] ;
char st1[25],st2[25];
char c_zero[6] = "00000";
char no[10];


FILE *fp1;


int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )
{
	int handle0,grhandle0 ;

 in =(char*)malloc(sizeof(char)*inwidth*inheight);


//LCD表示初期設定
	// DXライブラリの初期化
	if( DxLib_Init() < 0 ) return -1;

	//描画Windowsのサイズ設定
	SetGraphMode( WindowWidth , WindowHeight , 32 ) ;


	ChangeWindowMode(TRUE); // ウィンドウモードに設定

	

	SetDrawScreen( DX_SCREEN_BACK ); //描画先を表画面に設定

	handle0 = MakeRGB8ColorSoftImage(inwidth,inheight) ;
	
	image = ( BYTE * )GetImageAddressSoftImage( handle0 ) ;
	



for(LOOP = START;LOOP <= END;LOOP++){


//入力画像データFILE名作成

	//Input_image Read from FILE

    sprintf(no,"%d",LOOP);
	cno = (int)(strlen(no));

	sprintf(st1,"%d",inwidth);
	sprintf(st2,"%d",inheight);


	strcpy(ch1,"");
	strcat(ch1,st1);
	strcat(ch1,"_");
	strcat(ch1,st2);
	strcat(ch1,"_");
    strcat(ch1,"NoiseTest");
	strncat(ch1,c_zero,5 -cno);
	strcat(ch1,no);
	strcat(ch1,".raw");

	
//Buffer確保

	//Input_image Read from FILE
	

   fp1 = fopen(ch1,"rb");
   if(fp1 == NULL){
	   printf("Input FILE Error!!\n");
	   getchar();
	   return -1;
   }
   	  
	    fread(in,sizeof(char),inwidth*inheight,fp1);
		fclose(fp1);
	


//	 //fp1 = fopen("OutImg.raw","wb");
//	 //if(fp1==NULL){
//		// printf("Output file Error!!\n");
//		// return -1;
//	 //}
//  //
//	 //fwrite(pDst8u_1,sizeof(Ipp8u),inwidth*inheight,fp1);
//	 //
//	 //fclose(fp1);


//*************
//初期画面表示
//*************
	 	 
	ClearDrawScreen();//ScreenのClear

	// 白色の値を取得
	Color = GetColor( 255 , 255 , 255 ) ;

StartTime0 = GetNowCount() ;

//Thread数の設定
omp_set_num_threads(4);
#pragma omp parallel for
	// 入力データを画面表示メモリにSetする。
	for( i = 0; i <inwidth*inheight; i ++ )
	{

         image[i*3] = in[i];
      image[i*3 + 1] = in[i];
             image[i*3 + 2] = in[i];
		
			
	}

 EndTime0 = GetNowCount() ;

	// グラフィックハンドルを作成
	grhandle0 = CreateGraphFromSoftImage( handle0 ) ;

	
	// グラフィックハンドルを描画
	 DrawGraph( 0, 0, grhandle0, FALSE ) ;
	 

	 DrawString( 20 , 0 , ch1 , Color );
	 DrawFormatString( 20, 20 , Color, "Memory Write Time:%d[msec]\n",EndTime0-StartTime0 ) ;

	//LCD Vsync 2Wait(30FPS)
	WaitVSync(1) ;

	ScreenFlip(); //裏画面を表画面に反映

	//メモリ読み込んだ画像を消去する。
	//これを入れないと、多数の静止画を読み込んだ時、メモリが更新されなくなる。
	InitGraph() ;

	}

// 使い終わっったハンドルを解放
DeleteSoftImage( handle0 ) ;

//Memory解放
free(in);


	// 使い終わったら解放
	DeleteSoftImage( handle0 ) ;	

	// キー入力待ち
	WaitKey();
	

	// DXライブラリの後始末
	DxLib_End();

	// ソフトの終了
	return 0;
}

Re: Handleへの高速書き込みをしたいのですが。

Posted: 2012年11月28日(水) 10:58
by softya(ソフト屋)
MakePAL8ColorSoftImageの方を使えば1chの256階調のグレイスケールに出来ると思いますが如何でしょうか?

Re: Handleへの高速書き込みをしたいのですが。

Posted: 2012年11月28日(水) 20:18
by yoshihingis
Softya様、早速のご返事ありがとうございます。
MakePAL8ColorSoftImageの方を使う。ですが
パレットNo.0 R 0 G 0 B 0
パレットNo.1 R 1 G 1 B1
(途中略)
パレットNo.255 R 255 G 255 B 255

というパレットをあらかじめ作っておけば、表示したいグレースケール画像のデータをパレットナンバーとして書き込めば1CHデータの書き込みで済むという考え方でよろしいでしょうか?
 C言語初心者、DXライブラリ初心者なので、お手数をおかけしますが、ご回答いただければ幸いです。

Re: Handleへの高速書き込みをしたいのですが。

Posted: 2012年11月28日(水) 21:00
by softya(ソフト屋)
まぁ、試してもらったほうが速いと思います。
やってみないと分からないでしょうから、やってみてください。

Re: Handleへの高速書き込みをしたいのですが。

Posted: 2012年11月29日(木) 11:39
by yoshihingis
softya様

 一応、下記のようなコードで、1CH書き込みにて不具合なく動画表示できております。
 ただ、BGRの3CH書き込みに比較して、速度向上は僅かです。
 いろいろとご助言ありがとうございました。

コード:

#include "DxLib.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <omp.h>


int WindowWidth = 1600;
int WindowHeight = 1200;

int LOOP;
int START = 0;
int END   = 5954;
//int END = 3090;
//int END   = 0;


//int inwidth = 1700;
//int inheight = 1133;

//int inwidth = 1500;
//int inheight = 1000;

//int inwidth = 1400;
//int inheight = 933;

//int inwidth = 1300;
//int inheight = 866;

//int inwidth = 1200;
//int inheight = 800;

//int inwidth = 1100;
//int inheight = 733;

int inwidth = 1000;
int inheight = 666;


int Color;

int outwidth = 0;
int outheight =0;

int x,y,i,j,cno,xx=0;

int pBufferSize = 0;

BYTE *image;

int thread_num = 4;

char ch1[512],ch2[512] ;
char st1[25],st2[25];
char c_zero[6] = "00000";
char no[10];


char *in;

FILE *fp1;


int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )
{
	int handle0,handle1, grhandle0,grhandle1 ;


	in = (char*)malloc(sizeof(char)*inwidth*inheight);


//LCD表示初期設定
	// DXライブラリの初期化
	if( DxLib_Init() < 0 ) return -1;

	//描画Windowsのサイズ設定
	SetGraphMode( WindowWidth , WindowHeight , 32 ) ;


	ChangeWindowMode(TRUE); // ウィンドウモードに設定

	
	SetDrawScreen( DX_SCREEN_BACK ); //描画先を表画面に設定

	// 空のパレットカラー画像を作成する
	
	handle0 = MakePAL8ColorSoftImage(inwidth,inheight) ;

	//パレットの作成
	for(i = 0;i < 256;i++){
		SetPaletteSoftImage(handle0,i,i,i,i,0);
	}
		
	image = ( BYTE * )GetImageAddressSoftImage( handle0 ) ;
	


for(LOOP = START;LOOP <= END;LOOP++){


//入力画像データFILE名作成

	//Input_image Read from FILE

    sprintf(no,"%d",LOOP);
	cno = (int)(strlen(no));

	sprintf(st1,"%d",inwidth);
	sprintf(st2,"%d",inheight);


	strcpy(ch1,"");
	strcat(ch1,st1);
	strcat(ch1,"_");
	strcat(ch1,st2);
	strcat(ch1,"_");
    strcat(ch1,"NoiseTest");
	strncat(ch1,c_zero,5 -cno);
	strcat(ch1,no);
	strcat(ch1,".raw");

	
//Buffer確保

	//Input_image Read from FILE

	
   fp1 = fopen(ch1,"rb");
   if(fp1 == NULL){
	   printf("Input FILE Error!!\n");
	   getchar();
	   return -1;
   }
   	  
	    fread(in,sizeof(char),inwidth*inheight,fp1);
		fclose(fp1);
	
	 

//*************
//初期画面表示
//*************
	 	 
	ClearDrawScreen();//ScreenのClear

	// 白色の値を取得
	Color = GetColor( 255 , 255 , 255 ) ;

omp_set_num_threads(4);
#pragma omp parallel for

	for( i = 0; i <inwidth*inheight; i ++ )
	{
		image[i] = in[i];
	}


//	// グラフィックハンドルを作成
	grhandle0 = CreateGraphFromSoftImage( handle0 ) ;

	
	// グラフィックハンドルを描画
	 DrawGraph( 0, 0, grhandle0, FALSE ) ;


	//LCD Vsync Wait
	WaitVSync(1) ;

	ScreenFlip(); //裏画面を表画面に反映

	//メモリ読み込んだ画像を消去する。
	//これを入れないと、多数の静止画を読み込んだ時、メモリが更新されなくなる。
	InitGraph() ;

	}

// 使い終わっったハンドルを解放
DeleteSoftImage( handle0 ) ;

free(in);

	// 使い終わったら解放
	DeleteSoftImage( handle0 ) ;	

	// キー入力待ち
	WaitKey();
	

	// DXライブラリの後始末
	DxLib_End();

	// ソフトの終了
	return 0;
}

Re: Handleへの高速書き込みをしたいのですが。

Posted: 2012年11月29日(木) 11:47
by softya(ソフト屋)
ただのバイト転送なのでメモリ効率を考えるとforをパラレル化しない方が早いかもしれません。
あとmemcpyなどほうが効率的に転送してくれるかも知れませんので試してみて下さい。