• ベストアンサー

C言語

座標から画像の値を読み出すプログラムを教えてください。REDHATLinuxを使用しています。

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

  • ベストアンサー
回答No.8

BMPの場合。。。BMPファイルを(windows版の情報ヘッダ,24bitカラー,無圧縮,パレットなし)と固定してしまえば、画像データはファイルの54バイト目から入っていると思います。 ただし、データ順が一般的な走査順と違って、左下からになります。画素データは青緑赤の順に24ビットで、横幅が4バイト境界になるようにダミーデータが入ります(横1024ならダミーなしですね)。 linuxということでちと気になるのは、BMP形式のデータはリトルエンディアンで格納されています。1バイトずつファイルから読んでくれば問題ないですが、マシン(またはOS)によってはビッグエンディアンに変換が必要なです。 (参考)BMPファイルのヘッダ概要 オフセット 内容とサイズ ------------------------------------------------------------------- 0     ファイルタイプ(2バイト) 'BM'固定 2     ファイルサイズ(4バイト) 6     予約(2バイト+2バイト) 常に0 10    ファイル先頭から画像データまでのオフセット(4バイト) ------------------------------------------------------------------- 14    情報ヘッダのサイズ(4バイト) たぶん40 18    画像の幅(ピクセル)(4バイト) 22    画像の高さ(ピクセル)(4バイト) 正負で方向違う 26    プレーン数(2バイト) 常に1 28    1画素あたりのデータサイズ(2バイト) 24のはず 30    圧縮形式(4バイト) 0のはず 34    画像データ部のサイズ(4バイト) 38    横方向解像度(4バイト) 42    縦方向解像度(4バイト) 46    パレット数(4バイト) たぶん0 50    重要パレットインデックスの数(4バイト) ------------------------------------------------------------------- 54    画像データ 本当の開始位置はヘッダを見ること -------------------------------------------------------------------

tadashi1111
質問者

補足

ありがとうございます。上のは構造体の宣言なのでそれを用いてやってみます。一度回答を締めてもう一度質問しますね。

その他の回答 (7)

回答No.7

参考まで、rawフォーマットのデータ(test.raw)をpicに格納して、ヒルベルト走査してdataに入れてファイルに書き出します。画像データは横16ドット*縦16ドット*RGB(24bit)=768バイトです。 #include <stdio.h> #define SIZE 16 /* データ用変数 */ unsigned char pic[SIZE][SIZE][3]; int data[SIZE*SIZE]; /* intが16bitの時はlongにする */ int idx; /* ヒルベルト曲線用データ */ int dx[8][4]={{0,0,1,1},{1,0,0,1},{0,1,1,0},{1,1,0,0},{0,1,1,0},{1,1,0,0},{0,0,1,1},{1,0,0,1}}; int dy[8][4]={{0,1,1,0},{0,0,1,1},{1,1,0,0},{1,0,0,1},{0,0,1,1},{0,1,1,0},{1,0,0,1},{1,1,0,0}}; /* ヒルベルトスキャン */ void hilbert(int n, int pattern, int x, int y) {  if (n>1) {   hilbert(n/2, (pattern+4)%8, x+dx[pattern][0]*(n/2), y+dy[pattern][0]*(n/2));   hilbert(n/2, pattern, x+dx[pattern][1]*(n/2), y+dy[pattern][1]*(n/2));   hilbert(n/2, pattern, x+dx[pattern][2]*(n/2), y+dy[pattern][2]*(n/2));   hilbert(n/2, 7-pattern, x+dx[pattern][3]*(n/2), y+dy[pattern][3]*(n/2));  } else {   /* XY座標から画素値(24bit)を取得 */   data[idx++] = ((int)pic[x][y][0]<<16) | ((int)pic[x][y][1]<<8) | (int)pic[x][y][2];  } } int main(void) {  FILE *fp;  if ((fp=fopen("test.raw","rb"))==NULL) { printf("infile open error\n"); return -1;}  if (fread(pic,sizeof(unsigned char),SIZE*SIZE*3,fp)!=SIZE*SIZE*3) { printf("file read error\n"); fclose(fp); return -1;}  fclose(fp);  idx=0; hilbert(SIZE,0,0,0);  if ((fp=fopen("result.dat","wb"))==NULL) { printf("outfile open error\n"); return -1;}  if (fwrite(data,sizeof(int),SIZE*SIZE,fp)!=SIZE*SIZE) { printf("file write error\n"); fclose(fp); return -1;}  fclose(fp);  return 0; } ヒルベルトのところはさっき思いついたやり方なのでバグありかもしれません。。。

tadashi1111
質問者

お礼

うまく動きませんでした。><。 bpm方式も同じ用な感じですか?

tadashi1111
質問者

補足

ありがとうございます★やってみます。私は画像データを1024*1024にしたいにでそれでやってみますね。

  • kyrsche
  • ベストアンサー率41% (7/17)
回答No.6

またまたアドバイスということで。 #今回は裏付け無しなので、ちょっとあやふや(^_^;; RAW形式は、例えばビデオカードのメモリの状態そのままを ファイルに切り出したと思ってもらえればよいです。 英単語で「未処理の」「生の」という意味があります。 BMP形式は、このRAW形式にBMPヘッダが付いたフォーマットと 思ってもらえればよいです。 Binary Mapped Picture だか、そんな感じの略語です。 どちらも、24bit(32bit)フォーマットであれば、RGBの各レベルが 1ピクセル分格納されます。 (RAWとBMPではRGBの出現順番が違うかもしれません) RGBに分かれないのは、555/655といった1バイトのpacked形式や、 8bitグレースケールの場合、またインデックスカラー(パレットカラー)の場合です。 #呼び名はこれでよかったのか心配・・・(汗 RAW形式は、配列に格納した場合にインデックスがそのまま ラスター位置になりますが、BMP形式は、ラスター位置に更に BMPヘッダ分のオフセットが付きます。 また、RAW形式は左から右、上から下の順でデータを格納しますが、 BMP形式は左から右は同じですが、下から上にデータを格納します。 (WindowsのBMPは確かそうです。unixのBMPは違ったかもしれません) ですので、BMP形式はヘッダのオフセットと上下逆のアクセスが 必要になります。RAW形式だと、この操作がいりません。 ちなみにラスター位置は、ディスプレイの走査順に見た位置で、 左から右、上から下となります。 #ラスター位置だと、画像データと位置情報が同一になるので #処理がしやすく(=分かりやすく)なります。 ですので、画像を扱いたい(プログラムで画像処理をしたい)と いったときに、特に要求が無ければRAW形式の方が 余計な処理(=プログラム)を考えなくても良い利点があります。 その代わり、用意する画像を作るのに特殊な方法が必要になります。 #例えば、JaritenCatさんの例のように 画像処理は、結局は配列のデータをどういじるかですので、 どんな状態で配列に格納しているのかを押さえていると、 どんなデータ形式で格納されていても適切なアクセスができます。 いま、tadashi1111さんがプログラムにかけられる時間(BMP形式)と、 理解・データの準備にかけられる時間(RAW形式)を天秤に掛けて、 傾いた方を選択すると良いと思います。 ちなみに、tadashi1111さんはどんな答えをほしいのでしょう? 今はファイルアクセスのサンプルコードでしょうか?

tadashi1111
質問者

お礼

一度回答をしめてまた新たに質問しますね。

tadashi1111
質問者

補足

BMP方式でやりたいと思います。 C言語の場合、bmpファイルの構造は1画素ごとにRGBがワード単位で多重されているのではなく、1画素ごとに(RGB)の3次元ベクトルを配置する構造をとっているいるようです。よって、たとえば画像imgの(i,j)画素は img[i][j][k]と記述されるようです。ここで、k=1がR、k=2がG、k=3がBの値を表すことになるそうです。と聞きました。 圧縮するまでのBMP方式画像をヒルベルトスキャンし、その座標ごとの画素値を配列にし適当なファイル名をつけディスクに書き出したいんです。圧縮するプログラムはあるのですが><。

  • kyrsche
  • ベストアンサー率41% (7/17)
回答No.5

取得した画像を圧縮したい(圧縮率を出したい)、ということと、 JaritenCat さんのフォローから、私もなんとなく(^_^; 二次元画像を扱う場合、普通は一次元のデータに変換して加工処理を 行いますが、通常の画像の格納方法はラスター形式なのでX軸が回帰する 部分で連続しない無関係のデータになってしまう。 この部分を効率よく処理(圧縮)するために二次元の情報を持ちつつ 一次元にする変換方法として、ヒルベルトスキャンがある。 この変換を事前に行うことで、圧縮効率の向上が見られるかどうか、 そしてどの程度の向上があるかを判断したい、ということですね(^_^;; #かなり説明チックですね・・・。 やり方としては、JaritenCat さんがだいたい書かれてますのでそちらを(^_^;;; ファイルアクセス(read/write)と、配列からヒルベルトスキャンを行う 関数を組み合わせればよいと思います。ファイルアクセス処理は、C言語の 参考書であれば、だいたい載っていますので、そちらを参考に。 ヒルベルトスキャンは・・・自作だとちょっと面倒かもしれませんので、 出来合いのライブラリを借用(フリー公開のものを(^_^;;)して作るほうが 良いでしょうね。 #C Magazine2000年10月号にそういう特集があるみたいですね。 #ソースコードも公開されているようです。 #googleで「ヒルベルト」「ソース」「C」で検索して最初の方に出てくるようです。 #ただ、C++ for VC++なので、ちょっとクセがあるかなーと思いますが。 ##「クセ」は、Linuxでそのままでは使用できなさそうという意味で。 私は、ここ数年来Java屋さんなので C/C++ はちょっとつらいですね(^_^;; #心はC屋さんのつもりなのですが・・・(>△<

tadashi1111
質問者

補足

ありがとうございます。ヒルベルトスキャンのプログラムはいちおうできました。結果は(0,0)(0,1)(1,1)・・・・ という感じで。それからできなくて困ってます><。

回答No.4

なんとなくやりたい事は分かりました。 画像はBMP形式ではなくRAW形式ならヘッダなしにできるのでプログラムが簡単になります。 プログラムは、 (1)画像データを読みながら内部メモリ(2次元配列)に格納 (2)ヒルベルトスキャンの座標を計算して内部メモリ(1次元配列2個)に格納 (3)上で求めた座標から該当する画素の値を別のメモリ領域(1次元配列)に代入 (4)圧縮 (5)ファイルに書き出し という手順ですね。 RAWフォーマットのデータは、photoshopで作ることができます。ヒルベルトスキャンするので2^n*2^nサイズの画像ですね。RGB各8ビットの画像だとすると、photoshopで保存するときに汎用フォーマット(*.RAW)を選んで、ヘッダサイズを0にして、インターレースにチェックして保存します。 データは左上から順に、RGBRGBRGB・・・の順に並びます。 純粋に画像データだけでヘッダがないのでプログラムは簡単になります。 ファイルの読み込みは、fopenしてfgetcで1バイトずつ読んで配列に格納し、読み終わったらfclose。 いろいろ計算して、ファイルに書き出すのは、fopenしてfputcで1バイトずつ書き出せばいいでしょう。 そういえば、15年ぐらい前にヒルベルトスキャン+ランレングスで画像圧縮しようとしていました。。。懐かしい

tadashi1111
質問者

補足

RAW方式とBMP方式の違いはなんでしょうか?私はBMP方式でやりたいです。他の人に聞いたらRGBにわけなくてもよいと聞きましたが分けなくてもできますか?

  • kyrsche
  • ベストアンサー率41% (7/17)
回答No.3

レヨナという画像フォーマットがあるのですね。 勉強不足でした。 しかし、文章で説明できるということは、後はそのままプログラムに 落とせばよいのですが、難しいのでしょうか。 > JPEGだといけないんでBMP方式でないと画素値の値が取れないないのでBMPの画像にします。 > 画像をfil(file?)として読み込みヒルベルトスキャンして座標の(x、y)を出します。 > XYの長さを16としたとき(0,0)(0,1)(1,0)・・・・(0,14)(0,15)と256個の座標がでてきます。 > その値を画像に照らしあわせてその座標のとこの画素値を取り出したいんですけすど。 > そしてそれを(0,0)→file[0][0](0,1)→file[0][1]・・・みたいに2次元配列にし、次に1次元配列に直し > file[0][0]→g[0],file[0][1])→g[1]・・・と表したいんです。 いまいちやりたいことがストレートに読み取れません。 もっと前後というか、何がやりたいからコレが知りたいというのが 見えないので、明快に回答しにくいのです。 a「レヨナ→画像として閲覧したい」でしょうか、 b「画像→レヨナへの変換」でしょうか。 そして、矢印の間のドコが知りたいのでしょうか。 補足の内容から後者だとして、私なりの手順を考えると、こんな感じです。 1. 読み込ませたい画像ファイル(jpeg)を用意 2. 画像フォーマットを変換(jpeg→bmp) 3. bmpファイルを読み込み、画像データとしてメモリに格納 4. メモリの任意位置の画素値をヒルベルトスキャンにて取得 5. 取得した画素値を加工(ファイルに出力?) プログラムが出てくるのは3,4,5ですが、どこが分からないのでしょう?

tadashi1111
質問者

補足

説明下手ですみません。kyrscheさんのが要領がいいかもしれません。取得した画素値のファイルを圧縮したいんです。それでどれだけ圧縮できたかを調べたいんです。プログラムは3,4,5わかりません><。初心者で締め切り近くて困っています。

  • kyrsche
  • ベストアンサー率41% (7/17)
回答No.2

もうこし整理しましょう。 レヨナというのは画像フォーマットでしょうか。それともアーティスト? アーティストだとしたら、アーティストのどんな画像でしょうか。 CDジャケット?それとも、Web公開のサムネイル画像ですか? 次にその画像をどうしたいのでしょう? この辺りが分からないと、アドバイス使用にもできません。 もう少し補足をお願いします。

tadashi1111
質問者

補足

画像フォーマットです。でしたがJPEGだといけないんでBMP方式でないと画素値の値が取れないないのでBMPの画像にします。画像をfilとして読み込みヒルベルトスキャンして座標の(x、y)を出します。XYの長さを16としたとき (0,0)(0,1)(1,0)・・・・(0,14)(0,15)と256個の座標がでてきます。その値を画像に照らしあわせてその座標のとこの画素値を取り出したいんですけすど。そしてそれを(0,0)→file[0][0](0,1)→file[0][1]・・・みたいに2次元配列にし、次に1次元配列に直しfile[0][0]→g[0],file[0][1])→g[1]・・・と表したいんです。長くなりすみません。

  • kyrsche
  • ベストアンサー率41% (7/17)
回答No.1

まず扱いたい画像を決めてください。 次に扱う画像が、どういうフォーマットになっているかを調べてください。 そうすれば、おのずとどうすればよいかが分かります。 Unixはかなり離れてしまったので、良く覚えていませんが、 Xで扱える簡単な画像フォーマットがあったはずです。 一般的な画像(jpeg/gif/bmpなど)を扱いたいのであれば、 その画像フォーマットを読み込めるライブラリを探して利用するほうが 手っ取り早いと思います。 (bmpは何とかなると思いますが、gifやjpegは自分で解析するには大変です) じゃあ、どういうところを探せばそのライブラリが見つかるか というと、そこは私もよく分かりませんので(^_^; #googleなんかの検索サイトで頑張ってください(無責任ですが(^_^;;;)

tadashi1111
質問者

補足

画像はレヨナというのを使います。後はプログラムだけなんですが苦手でわかりません。

関連するQ&A