• ベストアンサー

C言語で.pgmの画像を作り、見る

Windows10のコマンドプロンプト上でC言語を使って.pgmの画像を作り、見ることができないので質問します。 以下のソースコードを実行してつくった。out.pgmファイルをGIMPとirfanviewというソフトを使ってみようとしましたが、GIMPはPNM 画像 エラーメッセージ 不正なファイルですと返し、irfanviewは invalid or unsupported PNMファイルと返し、何も表示されませんでした。 #include<stdio.h> int main(void){ FILE *fp; fp=fopen("out.pgm","wb"); fprintf(fp,"P5\n"); fprintf(fp,"#Image\n"); fprintf(fp,"256 256\n"); fprintf(fp,"255\n"); for(int i=0;i<256;i++){ for(int j=0;j<256;j++){ fwrite(&j,sizeof(unsigned char),1,fp); } } fclose(fp); return(0); } どなたかC言語で.pgmの画像を作り、見る方法を教えてくださいお願いします。

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

  • ベストアンサー
  • luka3
  • ベストアンサー率74% (295/397)
回答No.1

MinGWで試してみましたが、IrfanView・GIMPともにエラーもなく正常に表示されました。 コンパイラの環境を確認してみてください。 こういった時のデバッグ方法はこんな感じでしょうか。 ・IrfanViewで適当にPGMファイルを保存し、自分のout.pgmとどのように違うかStirlingなどのバイナリダンプソフトで比べてみる ・テキストベースの P2 フォーマットを作成してみて内容を確認する あと個人的に気になったのは >fwrite(&j,sizeof(unsigned char),1,fp); j が int なのに対し、1バイト分の出力です。 もし同じプログラムをビッグエンディアンの環境で実行した場合は、真っ黒の画像になりますのでご承知おきください。

situmonn9876
質問者

お礼

デバッグ方法を教えてくださり、ありがとうございます。ネットを使いながら試していきたいと思います。

その他の回答 (2)

  • chie65535
  • ベストアンサー率43% (8518/19363)
回答No.3

追記。 「バイナリモードでの書き込みはfwrite以外は使ってはいけません」と回答しましたが、ある条件を満たせばfprintfとfwriteを混ぜて使う事は可能です。 但し、混在させる場合は「ストリームバッファ」を意識して「おまじない」を行う必要があります。 その「おまじない」とは、fprintf使用後にfwriteを使う前に、fwrite使用後にfprintfを使う前に「fflushを呼び出す」という物です。 質問者さんのプログラムを修正すると以下のようになります。 #include<stdio.h> int main(void){ FILE *fp; unsigned char c; fp=fopen("out.pgm","wb"); fprintf(fp,"P5\n"); fprintf(fp,"#Image\n"); fprintf(fp,"256 256\n"); fprintf(fp,"255\n"); fflush(fp);/*おまじない*/ for(int i=0;i<256;i++){ for(int j=0;j<256;j++){ c=j; fwrite(&c,sizeof(c),1,fp); } } fclose(fp); return(0); } 以下、蛇足ですが。 fprintfがストリームバッファを使うか使わないか、fwriteがストリームバッファを使うか使わないか、は、決まりが無く、処理系に依存します。 どちらもストリームバッファを使わない実装をしている、どちらもストリームバッファを使う実装をしている、という場合、今回のような「実際の書き込み順序が前後してしまう」という現象は起きません(回答No.1の回答のように、何の問題も無く正常動作してしまいます) しかし、片方だけがストリームバッファを使う実装、もう片方が使わない実装をしているしている場合、fflushなどを使ってストリームバッファをファイルに吐き出すなど「おまじない」が必要になります。 このように「別のコンパイラでビルドしたらバグが出る」などの問題が起きるので「バイナリモードでの書き込みはfwrite以外は使ってはいけません」という話になるのです。ライブラリ関数を1種類だけしか使わなければ、どのコンパイラを使っても問題が起きることはありませんから。 今回は「コンパイラやライブラリが違うとバグが出たり出なかったりする」という、非常に厄介で発見し難い問題です。「他機種に移植したら何故かバグる」という、プログラマー泣かせの問題です。これで徹夜したプログラマーは大勢居ます。

  • chie65535
  • ベストアンサー率43% (8518/19363)
回答No.2

バイナリモードでの書き込みはfwrite以外は使ってはいけません。 fprintf系の書き込みは、ストリーミング処理、テキストバイナリ変換が行われる可能性があり、思い通りのバイナリイメージで書き込まれる保証はありません。 また、データを1バイト書き込む際に fwrite(&j,sizeof(unsigned char),1,fp); と書くと、何が書き込まれるか保証できません。 intサイズが4バイト(32ビット)だった場合、&jのアドレスが指すメモリに何が入っているか判りません。 リトルエンディアンの場合とビックエンディアンの場合で、intの中のバイト並びが変わるからです。 リトルエンディアンの場合は「偶然、上手く行く」のですが、ビックエンディアンの場合「常に0しか書き込まない」です。 1バイトのデータを正しく書き込みたいなら unsigned char c; と、確実に1バイトサイズである事が保証された変数を用意し c=j; fwrite(&c,sizeof(c),1,fp); と書きましょう。 因みに、貴方が書いたプログラムでは 1.空のファイルが生成され、ファイルがオープンされる 2.fprintfで書かれたデータがストリームバッファに書き込まれる(ファイルには書き込まれない) 3.fwriteで書かれたデータがファイルに直接書き込まれる(しかも何が書き込まれるか保証されない) 4.fcloseによりストリームバッファに書き込まれたデータがファイルに書き込まれる 5.ファイルがクローズされる という処理がされ、最初に書かれるべきデータが、画像データの後ろに書き込まれてしまい、pgmファイルとは似ても似つかない物が出来上がります。 出来上がったpgmファイルを「バイナリダンプ」してみて、想定したバイナリデータが想定した通りに並んでいるか確認して下さい。最初に256×256のデータがあって、その後ろに P5 #image 256 256 255 というヘッダーが書かれている筈です。 fprintfとfwriteは絶対に混ぜて使わない、リトルエンディアンとビックエンディアンを意識してプログラミングして下さい。 久しぶりに「cで絶対にやっちゃいけないプログラム」を見ました(笑)

situmonn9876
質問者

お礼

多くの間違いを分かりやすく指摘して、解決策を教えていただきありがとうございます。

関連するQ&A

  • c言語についての質問です

    #include<stdio.h> #define N 3 void inputAns(int *row,int *col,int data[][N]); void printAns(int ID,int data[][N]); int main(){ int row[N]={2,3,6},col[N]={8,5,3},answer[N][N]; int i,ID; printf("Input your ID number :\n"); scanf("%d",&ID);inputAns(row,col,answer); printAns(ID,answer); return(1); } void inputAns(int *row,int *col,int data[][N]){ int i,j; printf(" Input Answers of matrxi Q :\n"); for(i=0;i<N;i++){ for(j=0; j<N; j++){ printf("%2d+%2d=",row[i],col[j]); scanf("%d",&data[i][j]); } } } void printAns(int ID, int data[][N]){ FILE *fp; int i,j; fp=fopen("ans.dat","a+t"); fprintf(fp,"%d\n",ID); for(i=0; i<N; i++){ for(j=0; j<N; j++) fprintf(fp," %3d",data[i][j]); fprintf(fp,"\n"); } fclose(fp); } この百マス計算のプログラムの28行目からを書き換えて以下のような画面出力を求めたいです。 >./a.exe ID=50413001 [ 9/9 ] ID=50413002 [ 5/9 ] ID=50413003 [ 7/9 ] ID=50413004 [ 6/9 ] ID=50413005 [ 5/9 ] == correct rate === 4/5 3/5 5/5 5/5 1/5 4/5 4/5 1/5 5/5 =================== > 読み込むファイル(ans.dat)は以下のものです。 50413001 10 7 5 11 8 6 14 11 9 50413002 10 7 5 11 9 5 13 10 9 50413003 10 7 5 11 5 6 14 10 9 50413004 10 11 5 11 5 6 14 10 9 50413005 9 11 5 11 5 6 14 10 9 読み込みから集計がうまくいかず困っています。 どなたか教えてくれませんか?

  • C言語 ファイルポインタ

    度々同じプログラムで質問させてもらっています。 #include <stdio.h> #include <time.h> #include <math.h> #define N 10 void filewrite(int i,int a[]); void main(void){ int min,s,t,i,j,k,a[N]; srand((unsigned int)time(NULL)); for(i=0;i<N;i++) a[i]=rand()%10+1; for(j=0;j<i-1;j++){ min=a[j]; s=j; for(k=j+1;k<i;k++){ if(a[k]<min){ min=a[k]; s=k; } } t=a[j];a[j]=a[s];a[s]=t; filewrite(i,a); } } void filewrite(int i,int a[]){ int s; FILE *fp; fp = fopen("selection.txt","w"); if(fp == NULL)return; for(s=0;s<i;s++){ fprintf(fp,"%d,",a[s]); } fprintf(fp,"\n"); fclose(fp); } 途中経過もテキストファイルで出力したいのですが、このプログラムを実行すると最後の結果しか出力されません。 アドバイスをよろしくお願いします。

  • pgm画像入出力(C言語)

    画像入出力のプログラムを書いた(とあるサイトからパクった)のですが、出力画像のテキストデータが文字化けしてしまいます。原因究明お願いします。このプログラムでは2倍に変換していますが、そこは重要ではなく、入出力さえできればいいです。 OS:windows 文字コード:色々試したけどダメ。試してないものもあるかも。 プログラム #include <stdio.h> #include <stdlib.h> int main(int argc, char *argv[]) { FILE *fpi, *fpo; unsigned char idat; /* 引数のチェック */ if (argc != 3) { fprintf(stderr, "Usage: %s [input] [output]\n", argv[0]); exit(1); } /* 入力画像のオープン */ if((fpi=fopen(argv[1], "rb")) == NULL){ fprintf(stderr, "input file open error\n"); exit(1); } /* 出力画像のオープン */ if((fpo=fopen(argv[2], "wb")) == NULL){ fprintf(stderr, "output file open error\n"); exit(1); } /* 入力画像の読込み */ while (fread(&idat, sizeof(unsigned char), 1, fpi) == 1){ /* 2倍の変換 */ if (idat * 2 > 255) { idat = 255; } else { idat = idat * 2; } /* 変換データの書出し */ if(fwrite(&idat, sizeof(unsigned char), 1, fpo) != 1){ fprintf(stderr, "data write error\n"); exit(1); } } fclose(fpi); fclose(fpo); return (0); } コンパイル方法(cygwin) ./a 入力画像.pgm 出力画像.pgm

  • C言語 シンプルソート

    C言語始めて1年の初心者です。 #include <stdio.h> #include <stdlib.h> #include <string.h> #define MAXSIZE 10000 void swapData(char *x, char *y); void simpleSort(char data[], int first, int last); int main(int argc, char *argv[]) { int data[MAXSIZE][300]; int i, j, count; FILE *fp; if(argc != 2) { fprintf(stderr, "Usage: %s <filename>\n", argv[0]); exit(0); } if ((fp = fopen(argv[1], "r")) == NULL) { fprintf(stderr, "File %s is not found.\n", argv[1]); exit(0); } for(i = 0; i < MAXSIZE; i++) { if (fscanf(fp,"%s", &data[i]) == EOF) break; } simpleSort(data[], 0, i - 1); for(j = 0; j < i; j++) printf("%s\n", data[j]); } void swapData(char *x, char *y){ char tmp[300]; strcpy(tmp, x); strcpy(x, y); strcpy(y, tmp); } void simpleSort(char data[], int first, int last) { int i, j; for(i = first; i < last; i++){ for(j = i+1; j <= last; j++){ if(strcmp(&data[i], &data[j]) > 0) swapData(&data[i], &data[j]); } } } 読み込んだ文字データをシンプルソートするプログラムなんですが、コンパイルできません。 simpleSortの部分がおかしいみたいなんですが、見直しても先入観からか間違いを見つけられません・・・・ どなたか間違いを指摘していただけたら助かります。

  • 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・・・ みたいな感じです。

  • C言語のファイル入出力について

    for文の中でファイルの入出力をファイル名を変えながら行うことはできますか?作成したいプログラムは以下の通りになっています。 よろしくお願いします。 #include<stdio.h> main() { int i; FILE *fp; for(i=0;i<10;i++) {  fp=fopen("ココにiの値を入れたい.txt","w");  fprintf(fp,"%d\n",i);  fclose(fp); } return(0); }

  • C言語について質問です。

    ソートについて勉強していて、乱数列の要素数Nの値を変えていきバブルソートの交換回数、比較回数を数えるプログラムを作り、後は処理時間について調べたいのですが、処理時間を出力するのはどうやってやるのですか?教えてください。以下に乱数を生成するrand.cとバブルソートを行うbubblesort.cを記載します。これに処理時間を出力するようにしてもらいたいのですが、どうしたらいいですか?解説とソースファイルをよろしくお願いします。 rand.c #include <stdio.h> #include <stdlib.h> #include <time.h> #define N 1000 int num[N]; int makeDataFile ( void ) { int i; FILE *fp; char s[100]; int num[N]; srand ( ( unsigned )time ( NULL ) ); fp = fopen ("rand1.txt", "w" ); if ( fp == NULL ) exit(1); for ( i = 0; i < N; i++ ){ fprintf ( fp, "%d\n", rand()%100 ); } fclose ( fp ); fp = fopen ( "rand1.txt", "r" ); if ( fp == NULL ) exit(1); while( fgets ( s, sizeof (s), fp ) ) { printf ( s ); } fclose ( fp ); return N; } bubblesort.c #include <stdio.h> #include <time.h> extern int makeDataFile ( void ); extern int num[]; void BubbleSort ( int x[] , int n ); void Show ( int x[] , int n ); int comp; int swap; void BubbleSort ( int x[] , int n ) { int i, j, tmp; for ( i = 0; i < n-1; i++ ) { for ( j = n-1; j > i; j-- ){ comp++; if ( x[i] > x[j] ){ swap++; tmp = x[j]; x[j] = x[i]; x[i]= tmp; Show ( x , n ); } } } } void Show ( int x[] , int n ) { while ( n-- ) printf ( "%d " , *x++ ); printf ( "\n" ); } int main(void) { int i, j, n , tmp; FILE *fp; comp = 0; swap = 0; n = makeDataFile(); fp = fopen ( "rand1.txt", "r" ); if ( fp == NULL ) return 1; for ( i = 0; i < n; i++ ){ fscanf ( fp, "%d", &(num[i] ) ); } fclose ( fp ); printf ( "\nbefore bubblesort\n" ); Show ( num , n ); printf ( "\n" ); printf ( "progress bubblesort\n" ); BubbleSort ( num , n ); printf ( "\n" ); printf ( "after bubblesort\n" ); Show ( num , n ); printf ( "\n" ); printf ( "count of comparisons : %d\n" , comp ); printf ( "count of swap : %d\n" , swap ); return 0; }

  • C言語 セグメンテーション違反

    最大値検索法のプログラムソースを書きましたが、 実行すると、セグメンテーション違反となってしまいます。 どこがおかしいのでしょうか? 分かる方、教えてください。 宜しくお願いします。 swapのソース #include <stdio.h> void swap(int *px,int *py); int main (void) { FILE *fp; if ((fp=fopen("file.txt","rt"))==NULL){ printf("File open error.\n"); //ファイルが無い場合のエラー処理// return 0; } int i,a[10]; for(i=0;i<100;i++){ fscanf(fp,"%d,",&a[i]); //ファイルから読み込み処理。// } fclose(fp); //初期データの並びの表示// for(i=0;i<10;i++) printf("[%d]=%d\n",i,a[i]); /*1.ソートすべきデータの中で最大のデータを見つけ、 2.そのデータを最後のデータと入れ替える。 最大データは配列のどこにあるのか⇒maxi              その値⇒max とする。*/ //データが10個の場合 int max,maxi,j; max=a[0],maxi=0; for(i = 0;i < 9; i++){ if(a[i + 1] > max){ max = a[i + 1]; maxi = i + 1; } swap(&a[maxi],&a[9-j]); for(j=0;j<9;j++){ printf("%d \n",j); printf("i=%d\n ",i); max=a[0], maxi=0; for(i=0;i<9-j;i++){ //最大値をもつデータ探索;(カウンタ変数) max++; //最大データと探索範囲最後のデータとの入れ替え: int n; n=maxi; maxi=max; max=n; printf("maxi=%d \n ",maxi); printf("i=%d\n ",i); printf("j=%d \n",j); } } if((fp=fopen("file.txt","wt"))==NULL){ printf("File open error.\n"); return 0; } for(i=0;i<100;i++){ fprintf(fp,"%d,",a[i]); } fclose(fp); } sortのソース #include<stdio.h> void swap (int *px,int *py); void swap (int *px,int *py) { int n; n =*px; *px = *py; *py = n; }

  • c言語による画像処理について

    いつもお世話になってます。 c言語を使った画像処理を学び始めました。 入力画像の白(RGB値255,255,255)以外の画像を黒(RGB値0,0,0) に変換するプログラムを作成したいと思っているのですが、 入力画像の大きさによっては正常に命令を実行してくれないことがあるので、 改善点をご教示いただきたいと考え投稿させていただきました。ソースプログラムは #include<stdio.h> #define nx 100 //画像の幅 #define ny 100 //画像の高さ int main(void) { FILE *fp,*fp2; int i,j; unsigned char header[54]; unsigned char screen[nx][ny][3]; /* ファイルから読む */ fp=fopen("input.bmp","rb"); //ビットマップ形式 ,24ビットカラー fread(header,1,54,fp); // ヘッダ(54バイト)を飛ばす */ fread(screen,1,nx*ny*3,fp); // 残りはデータ(最下行から順に入る) //(255,255,255)以外なら黒(0,0,0)に for(j=0;j<ny;j++) for(i=0;i<nx;i++) if(screen[j][i][0]!=255||screen[j][i][1]!=255||screen[j][i][2]!=255){ screen[j][i][0]=0; screen[j][i][1]=0; screen[j][i][2]=0; } fclose(fp); /* ファイルに書く */ fp=fopen("output.bmp","wb"); fwrite(header,1,54,fp); /* ヘッダ */ fwrite(screen,1,nx*ny*3,fp); /* データ */ fclose(fp); return 0; } となっています。ここで、画像の高さ、幅を100以下にすると正常に変換できなくなります。 どなたか原因がお分かりでしたらお知らせ願えないでしょうか?

  • C言語 教えて下さい!!!

    教えてください!! data01.txt というテストの得点が書き込んであるテキストファイルから得点を読み込んで、得点順に並べ替えて表示させるプログラミングなんですがコンパイルは成功します。 しかし、実行してみると全く違う結果になってしまいます。 どこが間違っているのか指摘してください。 #include <stdio.h> /* 構造体の宣言 */ struct data { int score; int rank; }d; /* 関数 */ void rank(struct data *x, int n) { int i, j; for ( i=0; i<n; i++) x[i].rank = 1; for ( i=0; i<n; i++) for ( j=0; j<n; j++) if(x[i].score < x[j].score) x[i].rank++; } /* main文 */ int main(void) { int a; struct data x[50]; /* ファイルから得点を読み込む */ FILE *fp; fp = fopen("data01.txt", "r"); for ( a=0; a<50; a++) x[a] = atoi(getc(fp); fclose(fp); /* 順位付け */ a = 50; rank(x,a); printf("Rank Score\n"); for ( a=0; a<50; a++) printf("%d %d\n", x[a].rank, x[a].score); return 0; } ちなみに data.txt は 左側の列は番号 右側の列が得点 1 50 2 62 3 73 4 42 5 99 6 10 7 68 8 54 9 87 10 98 11 54 12 30 13 15 14 60 15 78 16 98 17 65 18 75 19 32 20 99 21 80 22 64 23 52 24 31 25 99 26 10 27 20 28 5 29 65 30 53 31 54 32 35 33 45 34 23 35 26 36 97 37 88 38 99 39 56 40 42 41 32 42 56 43 56 44 54 45 0 46 54 47 80 48 99 49 54 50 56

専門家に質問してみよう