• ベストアンサー

画像を読み込む配列の確保。

C言語について質問です。 画像を読み込む時、その画像の幅、高さを入力し、そのサイズに見合った配列を確保します。その後ファイル名を入力し、配列に読み込むプログラムを作成しました。 メインの部分のみ記述します。 int xsize, ysize, i; unsigned char **src; char filename[30]; FILE *fp; printf("ファイル名を入力してください:"); scanf("%s", filename); printf("画像の幅:");scanf("%d", &xsize); printf("画像の高さ:");scanf("%d", &ysize); src = (unsigned char **)malloc(sizeof(unsigned char *) * ysize); for(i=0; i<ysize; i++) src[i] = (unsigned char *)malloc(sizeof(unsigned char) * xsize); fp = fopen(filename, "rb"); fread(src[0], sizeof(unsigned char), xsize * ysize, fp); このように記述し、エラーもなく実行できたのですが、srcをこのまま出力すると変?な画像となって出力されてしまいました。 上のように記述した場合、矛盾する場所はあるでしょうか? そして、この方法以外に配列を確保する方法はあるでしょうか?

質問者が選んだベストアンサー

  • ベストアンサー
  • Oh-Orange
  • ベストアンサー率63% (854/1345)
回答No.6

★最初に ysize 分のポインタを管理領域と呼んでいません。 ・プログラマが malloc(1000) として 1000 バイトを確保した場合、  実際のメモリ上には  (1)malloc() 関数がメモリ確保の管理情報を数バイト保持(8~16バイトほど)  (2)実際にプログラマが使用できる 1000 バイトの領域  となります。つまり、使用できる 1000 バイトの領域の先頭に数バイトのメモリ管理情報が  存在するのです。 ・詳しい内部の仕組みは分かりませんが、確保したメモリ領域をリストデータで管理していると  思います。リストデータはポインタで次々にデータをチェインしますよね。  そのとき、次のデータ位置を表すポインタや確保サイズなどの数バイトが malloc() 関数などの  メモリ管理情報(領域)として存在するわけです。 ・以上を踏まえて回答 No.4 を読んでみて下さい。  もう少し分かりやすく説明すると  char *a = malloc(1000);  char *b = malloc(2000);  char *c = malloc(3000);  char *d = malloc(4000);  の4つのメモリは合計で 10000 バイト確保され 10000 バイトを使用できます。  でも、実際のメモリ上には、メモリ管理情報(領域)=ヘッダが存在しますので  a…8 + 1000  b…8 + 2000  c…8 + 3000  d…8 + 4000  で合計 10032 バイトのメモリを消費します。なお、8 バイトが管理情報ですが、昔使っていた  コンパイラを調べたときのサイズです。今はどれくらいか分かりませんが数バイトはあります。 ・メモリを節約したい場合は、回答者 No.5 さんのマクロ関数が一番節約できると思います。  前回も同じような感じでアドバイスしたときにマクロ関数を紹介しようと思いましたが、  それを使うのがスッキリしなくて unsigned char **src を使って src[y][x] とアクセスしたいのかと  思いましたのでマクロ使用の紹介は控えました。が、他の回答者さんのお礼にマクロ関数のことが  よく分からないとなっていましたね。今回はマクロ関数を利用する方がメモリを節約できます。 ・マクロ関数を利用すれば、画像の横×高さのサイズ分だけ確保すればよいので src[] のポインタ分の  メモリは節約できます。 ・以上。malloc() などは『実際のメモリ使用量=メモリ管理情報(領域)+確保サイズ』です。

noconan
質問者

お礼

返答ありがとうございました。 丁寧に説明いただきありがとうございます。 いろいろと質問してしまいましたが、やっと理解できました。 mallocは『実際のメモリ使用量=メモリ管理情報(領域)+確保サイズ』つまりmallocを行わなければ、いくらポインタをmallocで確保したとしても管理領域は発生しないということですね。 自分が質問に書いた”ysize分のポインタを確保”これはポインタを確保しただけであり、この時点では管理領域は発生しておらず、その後自分が書いたソースのように記述すると、各行ごとに管理領域が発生してしまうが、Oh-Orangeさんが提示してくださったプログラムではそれが発生しない。 自分の勘違いの基は「ポインタ変数=管理領域」という思い込みに原因がありましたねorz このような理解でよいでしょうか? そして最後にもう1つ気がかりが・・・・ この質問で初めに答えてくださったプログラムについてです。 そのプログラムではbuffのアドレスをsrcへ格納しています。 もしその後free(src)を行った場合、buffへの影響はないでしょうか?

その他の回答 (5)

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.5

どうしても使うメモリを xsize * ysize (くらい: malloc の管理領域はどうしても必要だから) にするのであれば, src を unsigned char * で定義してマクロで逃げる. つまり #define src(i, j) src[(i)+xsize*(j)] というマクロを用意してメモリは src = malloc(xsize * ysize); のように確保する. そうすれば size(x, y) という形でアクセスできる, はず. 姑息だけど.

noconan
質問者

お礼

返答遅れて申し訳ありませんでした。 確かにマクロで  #define src(i, j) src[(i)+xsize*(j)]  このように記述すれば、2次元配列として扱うことができますね。  アドバイスをしていただき、ありがとうございました。

  • Oh-Orange
  • ベストアンサー率63% (854/1345)
回答No.4

★メモリ確保量を考えるのならば、一度に大きい配列を確保した方が良い。 >src = (unsigned char **)malloc(sizeof(unsigned char *) * ysize); >for(i=0; i<ysize; i++) > src[i] = (unsigned char *)malloc(sizeof(unsigned char) * xsize);  ↑の方法では、ysize 分のメモリ管理領域(数バイト)のサイズ分だけ無駄になります。  つまり、メモリ管理領域を 8 バイトと仮定して、ysize=1000px とすると  8バイト×1000px=8000バイト分の管理領域が必要になります。  でも、 >buff = (unsigned char *)malloc( sizeof(unsigned char) * xsize * ysize ); >src = (unsigned char **)malloc( sizeof(unsigned char *) * ysize );  ↑の方法ならメモリ管理領域は2つ分で済みます。→8バイト×2個=16バイト  8000バイトと16バイトでは、どちらがメモリ量を節約できるか分かりますよね。 ・malloc 関数などのメモリ確保では、数バイトの管理領域+確保容量の合計が実際のメモリ上に  確保されるサイズ(バイト)です。このような内部的な仕組みを考えていないと確保容量を本当に  節約するプログラムは記述できません。→知っていればの話ですけど。 ・以上。補足情報でした。

noconan
質問者

お礼

返答が遅れてしまい、申し訳ありませんでした。 ちょっと込み入ってて・・・ 確かに自分の方法では管理領域としてysize分を必要とする記述方法になりますね。 Oh-Orangeさんが記述された src = (unsigned char **)malloc( sizeof(unsigned char *) * ysize ); このプログラムもysize分のポインタを確保して、そのポインタの先頭アドレスをsrcに代入するという意味では 管理領域としてysize分を必要とする記述になり、自分が書いたプログラムと同じ管理領域にならないのでしょうか?

  • Oh-Orange
  • ベストアンサー率63% (854/1345)
回答No.3

★アドバイス ・src[0] のメモリ領域は xsize 分しか確保されていません。 >fread(src[0], sizeof(unsigned char), xsize * ysize, fp);  とするとメモリ領域が足りないため、正しく読み込めませんよ。  src[0]、src[1]、src[2]…src[ysize - 1]のメモリ領域は連続して確保されることは  ないと思います。通常、malloc() 関数ではメモリ管理の為に数バイトのヘッダ情報が  あるためメモリ領域が連続して確保されません。無理! 解決法: ・一度に大きい配列領域を確保してから以前に紹介した FuncSetArray() 関数のようなやり方で  unsigned char **src のポインタにセットして下さい。 ・下にサンプルを載せます。 サンプル: int xsize, ysize, i; unsigned char **src; unsigned char *buff; FILE *fp; // メモリの確保 buff = (unsigned char *)malloc( sizeof(unsigned char) * xsize * ysize ); src = (unsigned char **)malloc( sizeof(unsigned char *) * ysize ); // ファイルの読み込み fp = fopen( filename, "rb" ); fread( buff, sizeof(unsigned char), (xsize * ysize), fp ); fclose( fp ); // 縦軸の配列セット for ( i = 0 ; i < ysize; i++ ){  src[ i ] = &buff[ xsize * i ]; } : 処理 : その他: ・上記のサンプルではエラーチェックなしです。チェックして下さい。  連続したメモリ領域 buff を確保して、その領域に fread で読み込めばデータが必ず  連続して読み込まれます。ラインごとに分割してメモリを確保した場合は、すべての  データが連続しません。malloc 以外のメモリ確保関数でも同じです。 ・以上。参考に!

noconan
質問者

お礼

返答ありがとうございました。 自分もこの方法を考えましたが、確かにうまく格納できると思います。しかしメモリ確保の量を考えると、sizeof(unsigned char) * xsize * ysize + sizeof(unsigned char *) * ysizeになると思います。 できるだけxsize*ysizeにしようと思っていたのですがちょっと難しそうです。 しかしこの方法を用いれば確実に2次元配列で扱うことができるし、画像の保存時もbuffをfwrite関数の引数に与えればいいだけなので、ある意味一番効率が良い方法かもしれません。 アドバイスありがとうございました。

  • buriburi3
  • ベストアンサー率44% (353/792)
回答No.2

srcが連続領域である保障がありません。 fread(src[0], sizeof(unsigned char), xsize * ysize, fp); が何処に読み込まれるか不確実です。 fp = fopen(filename, "rb"); for(i=0; i<ysize; i++) {  src[i] = (unsigned char *)malloc(sizeof(unsigned char) * xsize);  fread(src[i], sizeof(unsigned char), xsize , fp); または src = (unsigned char *)malloc(xsize * ysize); fp = fopen(filename, "rb"); fread(src[0], xsize , ysize, fp); なのでは?

noconan
質問者

お礼

src = (unsigned char *)malloc(xsize * ysize); fp = fopen(filename, "rb"); fread(src[0], xsize , ysize, fp); 確かにこのプログラムなら正常に読み込めると思います。 しかし・・・私が説明不足でしたね。 わざわざ**srcを使用した理由は通常の2次元配列同様に亜通ことができるからです。 src[][]のように。 この画像を読んでから複雑な処理を行うため、二次元配列同様に扱えたらとても理解しやすくなるので、**srcを用いました。 アドバイスありがとうございました^^

  • asuncion
  • ベストアンサー率33% (2126/6288)
回答No.1

> srcをこのまま出力すると ここのコードを省略せずに書いてほしかったです。 ヘッダーファイルのインクルードや、関数の定義など、 どうせなら書かれたコードを全部出してみませんか?

noconan
質問者

お礼

返答ありがとうございました。 と、同時に申し訳ありませんでした。 確かにこの疑問がsrcを表示させる部分に間違いがある可能性も十分にあるため、全てのコードを乗せるのが定石だとは思ったのですが、自分が不安を持っている部分について主に質問したかったためこのように記述してしまいました。 申し訳ないです。 やはり全てのコードを乗せたほうが良いですよね。

関連するQ&A

  • 2次元配列の動的確保

    ある画像を読み込むため、その画像を格納できる幅、高さを持った配列を動的に確保しようと考えています。 幅をxsize、高さをysizeで次のように記述しました。 unsigned char **src; int i; src = (unsigned char**)malloc(sizeof(unsigned char*) * ysize); src[0] = (unsigned char*)malloc(sizeof(unsigned char) * xsize * ysize); for(i=1; i<ysize; i++) src[i] = (src[0] + i * xsize); わざわざポインタのポインタを使用したのは、動的に確保した配列を2次元的なアクセスをしたかったためです。 画像の読み込み時は fread(src[0], sizeof(unsigned char), xsize * ysize, fp); としています。 上に記述したソースは問題なく動作しました。 しかし、上の場合だと全ての配列を連続して確保することができません。つまりsrcでmallocを一回、src[0]でmallocを一回使っているため、ポインタの配列の直後に配列を確保する保障がありません。そこでいっぺんに確保することを考えました。 unsigned char **src; int i; src = (unsigned char **)malloc(sizeof(unsigned char *) * ysize + sizeof(unsigned char) * xsize * ysize); for(i=0; i<ysize; i++) src[i] = (unsigned char *)(src + sizeof(unsigned char *) * ysize + i * xsize); このように組み上げ、読み込み時は上のfreadと同様に記述したところエラーが出てしまいました。 やはり一行目のmallocで無理やりsizeof(unsigned char *) * ysize + sizeof(unsigned char) * xsize * ysize分確保するのは失敗だったのでしょうか?

  • 3次元配列でのポインタ

    唐突ですみません。 サイズが640*480の画像を180枚読み込むプログラムをポインタを使って作成しようと考えています。 以下で示すプログラムは画像を読み込むための作成したものですが、エラーが出てしまい実行することができません。 間違えている箇所があればご指摘お願いします。 また、そのほかに効率の良いやり方などがありましたらご教授願います。 #include <stdio.h> #include <stdlib.h> #include <math.h> #define xsize 640 #define ysize 480 #define round 180 #include "Input.h" void Input_task(unsigned char ***In); void main() {   static unsigned char ***In;   int i,j;   In=(unsigned char***)malloc(sizeof(unsigned char)*round);   for(i=0;i<round;i++)   {     In[i]=(unsigned char**)malloc(sizeof(unsigned char)*ysize);     for(j=0;j<ysize;j++)     {       In[i][j]=(unsigned char*)malloc(sizeof(unsigned char)*xsize);     }   }   Input_task(In); } Input.hの中身 void Input_task(unsigned char ***In) {   char filename[30];   int i,j,k;   FILE *fp;   for(i=0;i<round;i++)   {     sprintf(filename,"b20_%04d.raw",i);     fp=fopen(filename,"rb");    for(j=0;j<ysize;j++)     {       for(k=0;k<xsize;k++)       {         *(*(*(In+i)+j)+k)=(unsigned char)getc(fp);       }     }    fclose(fp);   } }

  • とあるプログラムを教えてほしいのですが

    はじめましてこんばんは hommado と申します。 じつは先週の授業でこんな問題を出されたんですがもしできたらとあるプログラムを教えてほしいのです。 問題は 「キーボードから何階調にするのかを読み込むことで、入力画像LAX.bmpを任意の階調数に変換する」という プログラムです。 一応下に素体のプログラムをおいたんで、其のプログラムに何か付け足す感じでお願いします。「/*******↓基本的には、この範囲に画像処理プログラムを書く****/」から 「 /********↑**************************************************/」の中にプログラムを書くかんじなのでもし分かったら教えてください。お願いします。 あと何か他の所に付け足すようなところがあったら教えてください ここから元のプログラム // Bitmapファイルを読み込んで, // 別のファイルに出力するだけのプログラムです #include<stdio.h> #define XSIZE 256 /* 画像の横サイズ*/ #define YSIZE 256 /* 画像の縦サイズ*/ void main(void) { int x,y; char fni[40],fno[40]; /* 入力ファイルと出力ファイルの名前を格納するための配列*/ unsigned char head[1078],buf[YSIZE][XSIZE]; /* 入力ファイル(ビットマップファイル)のヘッダ情報と輝度値情報を格納するための配列*/ unsigned char in_image[YSIZE][XSIZE]; /* 入力画像の画素の輝度値を格納するための配列*/ unsigned char out_image[YSIZE][XSIZE]; /* 出力画像の画素の輝度値を格納するための配列*/ FILE *fp,*fp2; /* ファイルポインタ*/ printf("ファイル名を入れてください:"); scanf("%s",fni); fp=fopen(fni,"rb"); /* 読み込み& バイナリモードでオープンする*/ /* 配列head にビットマップファイルのヘッダ情報が格納されます*/ fread(head,sizeof(unsigned char),1078,fp); /* unsigned char 型のデータ×個を配列head に読み込む*/ /* 配列buf にビットマップファイルの輝度値情報が格納されます*/ fread(buf,sizeof(unsigned char),XSIZE*YSIZE,fp); for(y=0;y<YSIZE;y++){ for(x=0;x<XSIZE;x++){ in_image[y][x]=buf[y][x]; /* 画像の左下の画素が座標buf[0][0] です*/ } } printf("読み込み終了しました!\n"); printf("出力ファイル名を入れてください:"); scanf("%s",fno); /*******↓基本的には、この範囲に画像処理プログラムを書く****/       ここにプログラムを書いてください!      (もしここ以外で、他の所で付け足すプログラムがあったら何行目に       何を書くのかも教えてください) /********↑**************************************************/ fp2=fopen(fno,"wb"); /* 書き込み& バイナリモードでオープンする*/ /* 配列head の内容を出力ファイルに書き込む*/ fwrite(head,sizeof(unsigned char),1078,fp2); /* 配列out_image の内容を出力ファイルに書き込む*/ fwrite(out_image,sizeof(unsigned char),XSIZE*YSIZE,fp2); fclose(fp); /* ファイルをクローズする*/ fclose(fp2); /* ファイルをクローズする*/ printf("作業完了!\n"); }

  • ポインタ配列の動的確保

    ポインタの配列の動的確保について教えてください。 入力した数値をポインタ配列に入れるプログラムです。 下記のように書いてみました。(見づらくてごめんなさい) #include<stdio.h> #include<stdlib.h> #define kensu 3 main() { char abc[kensu+1]={'A','B','C','\0'}; char *ptr[kensu]; int i; printf("3つの整数を入力して下さい。\n"); for(i=0;i<kensu;i++){ ptr[i]=(char*)malloc(sizeof(char)*10); if(ptr[i]==NULL){ printf("メモリの取得に失敗しました"); exit(1); } printf("整数%c:",abc[i]); fgets(ptr[i],10,stdin); if(ptr[i][strlen(ptr[i])-1]=='\n') ptr[i][strlen(ptr[i])-1]='\0'; } for(i=0;i<kensu;i++) free(ptr[i]); } ちゃんと動いているようです。 しかし、ポインタ配列の動的確保をネットで調べてみると、ポインタのポインタ(?)を使って、下記のように2度mallocしています。 #include <stdio.h> #include <stdlib.h> #define N 3 int main(void) { char** arr; int i,j; arr = (char**)malloc(N * sizeof(char*)); /* ポインタ配列を確保 */ /* 配列の要素それぞれにつき、メモリ領域を確保 */ for(i=0;i<N;i++) arr[i] = (char*)malloc(N * sizeof(char));   ・・・ ポインタの配列を宣言して、配列の各要素に動的確保するのと ポインタのポインタを宣言し、ポインタ配列を動的確保して、再度配列の要素に動的確保するのとでは、何か違いがあるのでしょうか? ポインタのポインタを宣言し、ポインタ配列を確保する必要性が良く分かっていないのです。 ネット等で調べて見たのですが、理解力がないのかよく分かりませんでした。 どうか教えてください。

  • 「動的確保した2次元配列のメモリ解放」を関数化したい

    質問タイトルの通りですが、 「動的確保した2次元配列のメモリ解放」をC言語で関数化したいと思っています。しかし、関数の引数には動的確保した配列の先頭アドレスのみ渡す形にしたいです。そのような場合の関数化は可能ですか? どうもうまくいかず、困っています。 以下、具体的に、サンプルソースを記述します。 わかる方、よろしくお願いします。 //====================================================// #include<stdio.h> unsigned char** AllocByteArray2d(int column, int row); void FreeByteArray2d(unsigned char** box); int main(voidls){ unsigned char array**; array = AllocByteArray2d(2, 3); FreeByteArray2d(array); return 0; } unsigned char** AllocByteArray2d(int column, int row){ unsigned char* box; box = (unsigned char**)malloc( sizeof(unsigned char*)*column ) int i; for(i=0; i<column; i++){ box[i] = (unsigned char*)calloc( row, sizeof(unsigned char)); if(box[i] == NULL) exit(EXIT_FAILURE); } return box; } //引数では配列の先頭アドレスだけ渡す形にしたい void FreeByteArray2d(unsigned char** box){ //ここをどう書いたらいいかわからない }

  • インラインアセンブラについて

    現在、インラインアセンブラを学んでいるものです。 開発環境は Visual Studio 2005 です。 プログラムは、unsigned char型の配列を3つ(src1, src2, ans)用意し、src1[i] + src2[i] = ans[i] というようにiを変数として、src1、src2それぞれの要素の加算を配列ansに格納する動作をインラインアセンブラで作成しています。 そして、高速化を目指しMMXを使用しているのですが、うまく動作しません。 動作結果としては配列ansに正しい解が代入されず、全ての要素が 205? になっています。 どこかに問題があるのですが、未熟な自分では間違いに気づくことができません。 ご指摘お願いいたします。  #include <stdio.h> #include <stdlib.h> #include <string.h> #define LEN 64 int main(void){ unsigned char *src1, *src2, *ans; unsigned char *t1, *t2, *t3; int i, j; src1 = (unsigned char *)malloc(sizeof(unsigned char) * LEN); src2 = (unsigned char *)malloc(sizeof(unsigned char) * LEN); ans = (unsigned char *)malloc(sizeof(unsigned char) * LEN); t1 = src1; t2 = src2; t3 = ans; i = LEN / 8; for(j=0; j<LEN; j++){ //配列src1、src2の初期化 src1[j] = j; src2[j] = j + 1; } _asm { mov ecx, i LOOPSTART: movq mm0, src1 movq mm1, src2 paddusb mm0, mm1 movq ans, mm0 add src1, 8 add src2, 8 add ans, 8 loop LOOPSTART emms } src1 = t1; src2 = t2; ans = t3; for(i=0; i<LEN; i++) printf("%d + %d = %d\n", src1[i], src2[i], ans[i]); return 0; }

  • C言語による画像処理で出力時に文字化け

    http://image.onishi-lab.jp/002.html#1 ここを参考にsobelオペレータによるエッジ検出をしようとしています。 fxとfyのところを考えるのですが、とりあえず1にして出力したら文字化けしました。 文字化けの原因を教えてください。 読み込む画像は横160ピクセル、縦70ピクセルのP2形式のpgmファイルです。 #include <stdio.h> #include <stdlib.h> int pgm_read(char *filename, unsigned char *pimage){ FILE *fp; if((fp=fopen(filename,"rb"))==NULL){ printf("ファイル%sが開けません\n",filename); exit(-1); } fscanf(fp,"P2\n160 70\n255\n"); //ヘッダを読み飛ばす fread(pimage,sizeof(char),160*70,fp); fclose(fp); return 0; } int pgm_write(char *filename, unsigned char *pimage){ FILE *fp; fp=fopen(filename,"wb"); fprintf(fp,"P2\n160 70\n255\n"); fwrite(pimage,sizeof(char),160*70,fp); fclose(fp); return 0; } main(){ unsigned char *image; //取り込む画像 unsigned char *edge; //エッジ画像 int x,y; int fx,fy; //オペレータグラジエントの強度 FILE *fp; image = malloc(sizeof(char)*160*70); //メモリの確保 edge = malloc(sizeof(char)*160*70); pgm_read("input.pgm", image); //ファイルの読み込み for(y=1;y<70-1;y++){ //Sobel オペレータ for(x=1;x<160-1;x++){ fx = 1;// ここを考える fy = 1;// ここを考える if(fx*fx+fy*fy>500) *(edge+160*y+x) = 0x00; //閾値より大きいところは黒 else *(edge+160*y+x) = 0xff; //それ以外は白 } } pgm_write("output.pgm", edge); //ファイルの書き込み free(image); //メモリの開放 free(edge); } 文字化けの様子は P2 160 70 255 ^@^@^@^@^@^@^@^@・・・ ^@\377\377\377・・・ みたいな感じです。

  • 行毎の黒のドット(ピクセル)数を教えていただけませんか?

    開発環境Microsoft Visual Studio .NET 2003 2値画像を読み込んだ時、各行毎の黒のピクセル(ドット)数を表示する プログラムを組もうとしているのですがわかりません。 画像読み込みまではできたのですがその後のプログラムがわかりません 誰か組んでいただけないでしょうか? #include <stdio.h> #include <process.h> #define Y_SIZE 3648 // 処理できる最大画像 #define X_SIZE 3648 #define HIGH 255 // 画像の最大強度値 #define LOW 0 // 画像の最小強度値 #define LEVEL 256 // 画像の強度レベル値 // BMPファイルのフォーマットに従って用意した変数 typedef unsigned short WORD; typedef unsigned long DWORD; WORD bfType; DWORD bfSize; WORD bfReserved1, bfReserved2; DWORD bfOffBits; DWORD biSize, biWidth, biHeight; WORD biPlanes, biBitCount; DWORD biCompression, biSizeImage, biXPelsPerMeter, biYPelsPerMeter, biClrUsed, biClrImportant; unsigned char image_in[Y_SIZE][X_SIZE][3]; // 入力カラー画像配列 unsigned char image_out[Y_SIZE][X_SIZE][3]; //出力カラー画像配列 unsigned char image_bw[Y_SIZE][X_SIZE]; //濃淡画像配列 unsigned char data_rgb[Y_SIZE][X_SIZE][3]; // RGB画像配列 //******************************************** // 24Bitビットマップファイル読み込み * //******************************************** void readBMP( char *filename, // BMPファイル名 unsigned char image[Y_SIZE][X_SIZE][3] // 24ビットRGB画像配列 ) { FILE *fp; int i, j, k; // ファイルオープン if ((fp = fopen(filename, "rb"))==NULL) { printf("readBmp: Open error!\n"); exit(1); } printf("input file : %s\n", filename); // ヘッダー情報読み込む fread(&bfType, sizeof(bfType), 1, fp); fread(&bfSize, sizeof(bfSize), 1, fp); fread(&bfReserved1, sizeof(bfReserved1), 1, fp); fread(&bfReserved2, sizeof(bfReserved2), 1, fp); fread(&bfOffBits, sizeof(bfOffBits), 1, fp); fread(&biSize, sizeof(biSize), 1, fp); fread(&biWidth, sizeof(biWidth), 1, fp); fread(&biHeight, sizeof(biHeight), 1, fp); fread(&biPlanes, sizeof(biPlanes), 1, fp); fread(&biBitCount, sizeof(biBitCount), 1, fp); fread(&biCompression, sizeof(biCompression), 1, fp); fread(&biSizeImage, sizeof(biSizeImage), 1, fp); fread(&biXPelsPerMeter, sizeof(biXPelsPerMeter), 1, fp); fread(&biYPelsPerMeter, sizeof(biYPelsPerMeter), 1, fp); fread(&biClrUsed, sizeof(biClrUsed), 1, fp); fread(&biClrImportant, sizeof(biClrImportant), 1, fp); // RGB画像データ読み込む for (i=0; i<(int)biHeight; i++) for (j=0; j<(int)biWidth; j++) { for (k=0; k<3; k++) { //fread(&image[i][j][2-k], 1, 1, fp); fread(&image[biHeight-i][j][2-k], 1, 1, fp); } } fclose(fp); } //********************************************** // RGBカラー画像を256諧調白黒濃淡画像へ変換 * //********************************************** void BMPto256BW( unsigned char image[Y_SIZE][X_SIZE][3], unsigned char image_bw[Y_SIZE][X_SIZE] ) { int y, x, a; for (y=0; y<(int)biHeight; y++) for (x=0; x<(int)biWidth; x++) { a = (int)(0.3*image[y][x][0] + 0.59*image[y][x][1] + 0.11*image[y][x][2]); if (a<LOW) a = LOW; if (a>HIGH) a = HIGH; image_bw[y][x] = a; } } //***************************************** //各行の黒色判定 //***************************************** //**************************************** // 白黒濃淡画像配列のコピー * //**************************************** void imageCopyBW( unsigned char image1[Y_SIZE][X_SIZE], unsigned char image2[Y_SIZE][X_SIZE] ) { int x, y; for (y=0; y<(int)biHeight; y++) for (x=0; x<(int)biWidth; x++) image2[y][x] = image1[y][x]; } void main(void) { char input[100], output[100]; int intensity; printf("入力画像ファイル名(*.bmp):"); scanf("%s", input); readBMP(input, image_in); // 画像の入力,RGB24ビットカラーBMP画像を配列に格納 //一列各行の黒色の数出力 }

  • C言語でファイル読み書きを早くしたい。

    いつも利用させてもらって助かっています。 あるプログラムを作成しているのですが、ファイル入力の部分がネックとなってしまって、全体が使いものにならない状況に陥っています。 たくさんのデータをfread1回で読み込むことにより、読み込み速度はずいぶんと改善されましたが、まだ圧倒的に遅い状況です。システムコールを使いましたが、ほとんど改善されませんでした。 読み込み/書き込みの速度を改善する方法として,SSDメモリを使ったりする方法があると思いますが,プログラムの観点から改善できるところはないでしょうか? 下に、ファイル読み込みの部分だけ記述したコードを添付させて頂いたので、改善できる点があれば、御指摘頂けると助かります。 なお、前提として, (1)データはスタック領域だと不足するので、ヒープ領域に確保 (2)データファイルは改行無しの一連のデータ とします。 ちなみに、環境は OS   : CentOS5.3 memory   : 6GB コンパイラ : gcc です。 よろしくお願いします。 //----------------------------------------------------- //通常バージョン #include <stdio.h> #include <stdlib.h> #define SIZE (512*1024*1024) //500MB int main(void) { unsigned long int i; unsigned char *data; FILE *fp; data = (unsigned char *)malloc(SIZE); if(data == NULL) { printf("メモリが確保できません\n"); exit(EXIT_FAILURE); } fp = fopen("filein.dat", "rb"); fread( data, sizeof( unsigned char), (int)SIZE, fp ); fclose(fp); /* //表示 for( i=0; i<SIZE; i++ ){ printf("%2x", data[i]); } puts(""); */ fp = fopen("fileout.dat", "w"); fwrite( data, sizeof( unsigned char), (int)SIZE, fp); fclose(fp); free(data); return 0; } //----------------------------------------------------- //readシステムコールを使ったバージョン #include <stdio.h> #include <stdlib.h> #define SIZE (512*1024*1024) //500MB int main(void) { unsigned long int i; unsigned char *data; data = (unsigned char *)malloc(SIZE); if(data == NULL) { printf("メモリが確保できません\n"); exit(EXIT_FAILURE); } int fd; fd = open( "filein.dat" ); read( fd, data, sizeof(unsigned char)*SIZE); close(fd); /* //表示 for( i=0; i<SIZE; i++ ){ printf("%2x", data[i]); } puts(""); */ FILE *fp; fp = fopen("fileout.dat", "w"); fwrite( data, sizeof( unsigned char), (int)SIZE, fp); fclose(fp); free(data); return 0; }

  • 配列のサイズ変更

    FILE *fp; char *fname = "test.txt"; unsigned char init[300]; int i = 0; int c; fp = fopen( fname, "r" ); if( fp == NULL ){ printf( "%sファイルが開けません\n", fname ); return -1; } while( (c = fgetc( fp )) != EOF ){ init[i] = c; i = i+1; } fclose( fp ); 自分のプログラムの中のこのようなテキストから文字を読んで配列に格納するような動作の中で、initを大きめにとっておいて配列に格納し終わったら余った空の配列を削除する、という機能を拡張したいのですがどのようにすればいいかわかりません。 どなたか教えていただけないでしょうか?

専門家に質問してみよう