dポイントプレゼントキャンペーン実施中!

プログラムemboss.cの機能を変えずに高速化したいです。

制約が2つあります。
1.画像のためのメモリはヒープ領域に動的に確保する。
2.結果画像が変わらない。

以下の制約を守っていただければ、どのように変更されても構いません。
とにかく消費時間の短縮を目指したいと思います。
どうぞ知恵をお貸しください。よろしくお願いします。

また、消費時間の短縮に繋がった改善点を簡単でけっこうですので説明してくだされば幸いです。

ソースは以下の場所にあります。
http://kansai2channeler.hp.infoseek.co.jp/cgi-bi …

コンパイル:gcc -Wall -O2 emboss.c
実行:time a.out

A 回答 (3件)

emboss関数しか見ていませんが...



間接参照が多すぎます。
ループを回すごとに右端の次元の添え字をインクリメントしているだけなので、ポインタで書き換えましょう。

他にも、dxやdyに絡む演算のうち、ループの外に出せるものは出してしまいましょう。コンパイル結果を見ればわかると思いますが、意外に最適化が効いていないものです。

後は、GCCのターゲットや、実際の実行環境次第になりますが...

一番内側のループは3回程度であれば開いてしまうのも効果があるかもしれません。

配列の要素を、UCHARではなくintにすることで、汎整数拡張によるオーバーヘッドがなくなります。ただし、そもそも汎整数拡張のオーバーヘッドがない、またはほとんどない環境もありますし、キャッシュのヒット率が低下する可能性もあるので要注意です。

細かな部分は他にもありますが、大体こんなところかと思います。
ところで、提示されているURLをクリックしただけではソースが開きません。また、質問文が編集される可能性も高いので、この質問にソースを補足してください。

この回答への補足

続きです。

/* ファイルを開く */
if((fp = fopen(fname, "rb")) == NULL) {
fprintf(stderr, "file(%s) can't open.\n", fname) ;
exit(1) ;
}
/* マジックナンバー読み込み */
count_limit=0;
sprintf(str_buf,"#");
while((str_buf[0]=='#') || (str_buf[0]=='\n') || (str_buf[0]=='\t') || (str_buf[0]==' '))
{
fgets(str_buf,1024,fp);
count_limit++;
if(count_limit > 1000)
{
fprintf(stderr,"ERROR: Irregal file format.\n");
exit(1);
}
}
strcpy(magic_num, str_buf);
magic_num[strlen(magic_num)-1]='\0'; /* \nを除く */
if(strcmp(magic_num, "P6") != 0)
{
fprintf(stderr, "ERROR: magic number(%s) not match.\n", magic_num) ;
exit(1) ;
}

/* 画像の幅(列数)と高さ(行数) */
count_limit=0;
sprintf(str_buf,"#");
while((str_buf[0]=='#') || (str_buf[0]=='\n') || (str_buf[0]=='\t') || (str_buf[0]==' '))
{
fgets(str_buf,1024,fp);
count_limit++;
if(count_limit > 1000)
{
fprintf(stderr,"ERROR: Irregal file format.\n");
exit(1);
}
}
sscanf(str_buf,"%d %d",max_retu,max_gyou);

/* 最大値 */
count_limit=0;
sprintf(str_buf,"#");
while((str_buf[0]=='#') || (str_buf[0]=='\n') || (str_buf[0]=='\t') || (str_buf[0]==' '))
{
fgets(str_buf,1024,fp);
count_limit++;
if(count_limit > 1000)
{
fprintf(stderr,"ERROR: Irregal file format.\n");
exit(1);
}
}
sscanf(str_buf,"%d",&max_val);
if(max_val > 255)
{
fprintf(stderr, "ERROR: Irregal max value.\n");
exit(1) ;
}

/* 画像読み込み */
fread((UCHAR *)&data_buf[0][0][0], sizeof(UCHAR), (*max_retu)*(*max_gyou)*3, fp);

/* ファイルを閉じる */
fclose(fp);
}

/* 動的確保されたCSQ形式の画像メモリからppmフォーマットの画像ファイルを作成 */
void write_ppm_csq_mem(UCHAR ***data_buf,char *fname,int width,int height)
{
FILE *fp;
int m, n;

if((fp = fopen(fname, "wb")) == NULL) {
fprintf(stderr, "file(%s) can't open\n", fname) ;
exit(1) ;
}

fprintf(fp, "P6\n") ; /* カラー画像かつバイナリーデータの記号 */
// fprintf(fp, "#\t%s\n", fname) ; /* #で始まるのはコメント行 */
fprintf(fp, "%d %d\n", width, height) ; /* 画像の幅(列数)と高さ(行数) */
fprintf(fp, "255\n") ; /* 最大値 */

for(m=0;m<height;m++)
for(n=0;n<width;n++)
{
fwrite(&data_buf[0][m][n], sizeof(UCHAR), 1, fp);
fwrite(&data_buf[1][m][n], sizeof(UCHAR), 1, fp);
fwrite(&data_buf[2][m][n], sizeof(UCHAR), 1, fp);
}

fclose(fp) ;
}

/* 動的確保されたCIP形式の画像メモリからppmフォーマットの画像ファイルを作成 */
void write_ppm_cip_mem(UCHAR ***data_buf,char *fname,int width,int height)
{
FILE *fp;

if((fp = fopen(fname, "wb")) == NULL) {
fprintf(stderr, "file(%s) can't open\n", fname) ;
exit(1) ;
}

fprintf(fp, "P6\n") ; /* カラー画像かつバイナリーデータの記号 */
// fprintf(fp, "#\t%s\n", fname) ; /* #で始まるのはコメント行 */
fprintf(fp, "%d %d\n", width, height) ; /* 画像の幅(列数)と高さ(行数) */
fprintf(fp, "255\n") ; /* 最大値 */

fwrite(&data_buf[0][0][0], sizeof(UCHAR), width*height*3, fp);

fclose(fp) ;
}

/* 3次元配列の動的生成 */
UCHAR ***malloc3Duchar(int dim1,int dim2,int dim3)
{
int i,j;
UCHAR ***c1,**c2,*c3;

if((c1 = (UCHAR ***)malloc(dim1*sizeof(UCHAR **))) == NULL)
error1("can't allocate in malloc3Duchar");

if((c2 = (UCHAR **)malloc(dim1*dim2*sizeof(UCHAR *))) == NULL)
error1("can't allocate in malloc3Duchar");

for(i=0;i<dim1;i++)
c1[i]=c2+dim2*i;

if((c3 = (UCHAR *)malloc(dim1*dim2*dim3*sizeof(UCHAR))) == NULL)
error1("can't allocate in malloc3Duchar");

for(i=0;i<dim1;i++)
for(j=0;j<dim2;j++)
c1[i][j]=c3+(dim2*i+j)*dim3;

return c1;
}

/* 3次元配列の解放 */
void free3Duchar(UCHAR ***point)
{
free(point[0][0]);
free(point[0]);
free(point);
}

/* エラー処理 */
void error1(char *message)
{
printf("%s\n",message);
exit(1);
}

補足日時:2007/06/10 03:35
    • good
    • 0

http://kansai2channeler.hp.infoseek.co.jp/cgi-bi …

これ、アクセスできませんでした。
別なところでソース出してもらえますか?

この回答への補足

以下がソースです。
長いので分割します。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef unsigned char UCHAR;

/* 画像サイズは変更不可 */
#define DIM1 960 /* 行数 */
#define DIM2 1280 /* 列数 */
#define DIM3 3

#define RED 0
#define GREEN 1
#define BLUE 2

#define N_REPEAT 200 /* 繰返し回数.消費時間測定時は必ず200とする. */

/* 動的確保されたCSQ形式の画像メモリからppmフォーマットの画像ファイルを作成(通常は未使用) */
void write_ppm_csq_mem(UCHAR ***,char *,int ,int);

/* 動的確保されたCIP形式の画像メモリからppmフォーマットの画像ファイルを作成 */
void write_ppm_cip_mem(UCHAR ***,char *,int ,int);

/* エンボス処理 */
void emboss(UCHAR ***, UCHAR ***, int, int, int, int);

/* ppmフォーマットの画像ファイルを動的確保したCIP形式の画像メモリに読み込み */
void read_ppm_cip_mem(UCHAR ***, char *, int *, int *);

/* 3次元配列の動的生成 */
UCHAR ***malloc3Duchar(int ,int ,int );

/* 3次元配列の解放 */
void free3Duchar(UCHAR ***);

/* エラー処理 */
void error1(char *);


/***** 注意点 *****/
/* 画像のためのメモリはヒープ領域に確保すること(宣言は利用不可とする) */
/***** 注意点 *****/

int main(int argc, char *argv[])
{
int i;
int dx; /* 横方向シフト量 */
int dy; /* 縦方向シフト量 */
int max_gyou; /* 入力画像の行数 */
int max_retu; /* 入力画像の列数 */
char in_fname[200]; /* 入力画像ファイル名 */
char out_fname[200]; /* 出力画像ファイル名 */
UCHAR ***org,***res;

if(argc < 4) /* 入力コマンドチェック */
{
printf("usage: a.out filename dx dy \n");
exit(1);
}
else
{
strcpy(in_fname,argv[argc-3]); /* 入力画像のファイル名 */
dx=atoi(argv[argc-2]); /* 横方向シフト量(右が正) */
dy=atoi(argv[argc-1]); /* 縦方向シフト量(下が正) */
}

org=malloc3Duchar(DIM1,DIM2,DIM3); /* 入力画像用3次元配列の動的確保 */
res=malloc3Duchar(DIM1,DIM2,DIM3); /* 出力画像用3次元配列の動的確保 */

read_ppm_cip_mem(org, in_fname, &max_gyou, &max_retu); /* 画像をファイルより読み込み */

if((max_gyou != DIM1) || (max_retu != DIM2)) /* 読み込んだ画像の行数と列数のチェック */
error1("Image size is wrong.");


/* エンボス処理(時間測定のため必ず200回行う.) */
for(i=0;i<N_REPEAT;i++)
{
emboss(res,org,dx,dy,max_gyou,max_retu);
}


in_fname[strlen(in_fname)-4]='\0'; /* 入力画像ファイル名から.ppm除く */
sprintf(out_fname,"/tmp/%s_out.ppm",in_fname); /* 出力画像ファイル名設定 */
write_ppm_cip_mem(res,out_fname,max_retu,max_gyou); /* 出力画像をファイルへ出力 */

free3Duchar(org); /* 入力画像用3次元配列の解放 */
free3Duchar(res); /* 出力画像用3次元配列の解放 */

return 0;
}

/* エンボス処理 */
void emboss(UCHAR ***ans, UCHAR ***org, int dx, int dy, int n_gyou, int n_retu)
{
int g,r,m;
int val;

for(g=0;g<n_gyou;g++) /* 1画素ずつ処理する */
for(r=0;r<n_retu;r++) /* 画像メモリ領域外にアクセスしないようにチェック */
if((g+dy >= 0) && (g+dy < n_gyou) && (r+dx >= 0) && (r+dx < n_retu))
for(m=0;m<3;m++)
{
val=org[g][r][m]-org[g+dy][r+dx][m]+128;
if(val > 255) /* 画素値は0以上255以下 */
ans[g][r][m]=255;
else if(val < 0)
ans[g][r][m]=0;
else
ans[g][r][m]=val;
}
else /* 算出できないところの画素値は128とする */
for(m=0;m<3;m++)
ans[g][r][m]=128;
}
/* ppmフォーマットの画像ファイルを動的確保したCIP形式の画像メモリに読み込み */
void read_ppm_cip_mem(UCHAR ***data_buf, char *fname, int *max_gyou, int *max_retu)
{
FILE *fp ;
char str_buf[1024] ;
char magic_num[8] ; /* マジックナンバー */
int max_val ; /* 画素値の最大値 */
int count_limit;

補足日時:2007/06/10 03:33
    • good
    • 0
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!