いつもお世話になってます。
c言語を使った画像処理を学び始めました。
入力画像の白(RGB値255,255,255)以外の画像を黒(RGB値0,0,0)
に変換するプログラムを作成したいと思っているのですが、
入力画像の大きさによっては正常に命令を実行してくれないことがあるので、
改善点をご教示いただきたいと考え投稿させていただきました。ソースプログラムは
#include<stdio.h>
#definenx 100//画像の幅
#defineny 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以下にすると正常に変換できなくなります。
どなたか原因がお分かりでしたらお知らせ願えないでしょうか?
No.4ベストアンサー
- 回答日時:
#3 訂正
自分的に256BMPメインで扱ってたんで一応確認してみましたが
24ビットだとちょっと変わった変化してます
24ビットカラーのとき横4で割り切れないピクセル数だと
データとしては 1Pixl×3バイト(BGR) + 余りバイト数
となっているようです
ここら辺は御自分でペイント使って出来たファイルの
中身調べれば分かると思います
上のような動作ですと#3で書いたコードでは結局動かないはずです
コードを全面的に書き直します(Windows前提のVCコード)
ついでにサイズはファイルからそのまま読んでます
エラー処理などは省いています
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
int main()
{
FILE *fp;
BITMAPFILEHEADERfileheader;
BITMAPINFOHEADERheader;
RGBTRIPLE*rgb;
unsigned char *screen;
intsize;
/* ファイルから読む */
fp=fopen("c:\\aaa.bmp","rb"); //ビットマップ形式 ,24ビットカラー
fread(&fileheader,sizeof(fileheader), 1,fp); // ヘッダ(54バイト)を飛ばす */
fread(&header,sizeof(header), 1,fp); // ヘッダ(54バイト)を飛ばす */
//size = ((header.biWidth % 4) == 0) ? (header.biWidth * header.biHeight * 3) : (header.biWidth * header.biHeight * 3) + header.biWidth % 4;
size = fileheader.bfSize - (sizeof(fileheader) + sizeof(header));
screen = (unsigned char *)malloc(size);
fread(screen,size,1,fp); // ヘッダ(54バイト)を飛ばす */
fclose(fp);
rgb = (RGBTRIPLE *)screen;
//(255,255,255)以外なら黒(0,0,0)に
for(int y = 0 ; y < header.biHeight ; y ++) {
for(int x = 0 ; x < header.biWidth ; x ++, rgb ++) {
if((rgb->rgbtRed != 255) || (rgb->rgbtGreen != 255) || (rgb->rgbtBlue != 255)) {
rgb->rgbtRed = 0;
rgb->rgbtGreen = 0;
rgb->rgbtBlue = 0;
}
}
char *addr = ((char *)rgb) + (header.biWidth % 4);
rgb = (RGBTRIPLE *)addr;
}
free(screen);
//別ファイルに書く分は手抜き
}
No.7
- 回答日時:
#6です。
>>添字の順番が逆になっています
>とのことですが、どうやら画像のデータは(y,x)という風に書かれている>ようなので、
>これで正しいと思っています。
もう一度よくみてください
screenの宣言は
> unsigned char screen[nx][ny][3];
で、添字の範囲は[0~(nx-1)][0~(ny-1)][0~2]となっています。
対して
> 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){
では[j=0~(ny-1)]i=[0~(nx-1)][0~2]を使おうとしています。
最初のプログラムではnx=100,ny=100なので入れ替わっても同じでしたが、これを
nx=200,ny=100
としたら
[0~(200-1)][0~(100-1)][0~2]と宣言して
[0~(100-1)][0~(200-1)][0~2]とで使おうとすることになります。
Cでは添字の範囲外のチェックを行いません。「添字が範囲外」というエラーは出ません。その添字で指定された領域をアクセスしようとします。
結果、たまたまそこにあった関係ない変数が書き変わったり、そもそもアクセス制限にかかって致命的はエラーとなったりします。
今回は最終的に動的確保で落ちつきそうなので、直接関係ないところではありますが、指摘されていただきました。
お返事ありがとうございます。
ご指摘いただいた内容をよく理解せず返答してしまいました。申し訳ございません。
確かに変数宣言時に
unsigned char screen[nx][ny][3];
となっていますね。
これでは添え字が間違っていると認めざるを得ません。
再度ご指摘いただかなければ誤った認識のままでいるところでした。
ご指摘、本当にありがとうございます
No.6
- 回答日時:
100x100のときも結果としてうまく読めてるみたいですが
> unsigned char screen[nx][ny][3];
と宣言しておいて
> 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){
と添字の順番が逆になっています。
この回答への補足
失礼しました。
御礼を送る相手を間違えてしまいました。
ご回答ありがとうございます。
>添字の順番が逆になっています
とのことですが、どうやら画像のデータは(y,x)という風に書かれているようなので、
これで正しいと思っています。
この認識は間違いなのでしょうか?
なるほど、そうなっていたのですね!
おかげさまで無事問題が解決しました。
たびたび質問に答えてくださり、本当にありがとうございます。
No.5
- 回答日時:
#4補足
#4に書いてあるコメントは元々のソースのコピーで残っててめちゃくちゃです
(直し忘れたのをそのまま乗せてしまいました環境はVC6++のコンソールアプリ)
一応データサイズ自分で求めましたがめんどくさいので結局
ファイル情報に記載してあるサイズ分を読むようにしています
(計算方法としてコメント行で記載してあるだけだと思ってください)
>char *addr = ((char *)rgb) + (header.biWidth % 4);
>rgb = (RGBTRIPLE *)addr;
ここでデータポインタを次の行の位置に合わせています
本来はエラー処理含めファイルの中身がBMPなのか
24ビットカラーなのか等もチェックする方がより正確なものになります
なるほど、そうなっていたのですね!
おかげさまで無事問題が解決しました。
たびたび質問に答えてくださり、本当にありがとうございます。
No.3
- 回答日時:
>自分のプログラムにどう組み込めばいいのか、ご教示願えませんでしょうか?
とっても安直な方法です
>#define nx 100 //画像の幅
#define nx_org 100 //画像の幅
int nx;
int main(void)
{
nx = (nx_org % 4) 0 ? nx_org : (nx_org / 4 + 1) * 4;
>unsigned char screen[nx][ny][3];
コンパイラ次第でエラーになったりならなかったりするので
エラーの場合
unsigned char *screen;
screen = memalloc(sizeof(unsigned char), nx * ny * 3);
などと変えてください
アロケーションした場合 free もお忘れなく
それ以外もともとの御自分のコードで動くはずです
(保管部分のデータに対しては一切操作してません)
コンパイル・確認して無くてここに直に書いたんで間違ってるかも
(イメージだけつたわりゃ良いかなと)
そのようにすればよかったのですか。
さっそくご教示いただいた部分をプログラムに取り込むと
>unsigned char screen[nx][ny][3];
の部分でエラー「定数式が必要です」
のエラーがでてしまいます。
unsigned char *screen;
screen = memalloc(sizeof(unsigned char), nx * ny * 3);
としてみましたが、こちらのプログラムの
>//(255,255,255)以外なら黒(0,0,0)に
以下がエラー(配列または、ポインタでない変数に添字が使われました)
となり、コンパイルできませんでした。
ポインタは扱ったことがないのでどのように変更すればいいのか分かりません。
恐縮ですが、この部分の対処法をご教示願えないでしょうか?
No.2
- 回答日時:
ビットマップは1ライン4バイト境界で作成しないといけませんが
その辺りの問題ではないですか?
それ以外はプログラム的に間違ってないと思います
4バイト境界になってないBMPを作るためには不足分のバイトを自分で
補ってファイルを作る必要があります
(その部分のデータは何でも良かったと思いますが0にしておいた方がいいとは思います)
例)
横 2pixl のBMP作りたいときは 横 4pixlのデータを作る
(2pxl分のデータは0にしておく)
ということです
BMP構造としては以下参照
http://www.kk.iij4u.or.jp/~kondo/bmp/
ご回答いただきありがとうございます。
おかげさまでbmpの内容について少し理解できました。対処する方針もわかりました。
しかしながら、実際に直接画像データを操作するとなると、勝手がわからず
>>4バイト境界になってないBMPを作るためには不足分のバイトを自分で
補ってファイルを作る必要があります
とのことですが、具体的にはどのように操作すればよいのでしょうか?
お示しいただいたサイトのプログラム
line = (Width * BitCount) / 8; // 1 ラインあたりのデータ数
if ((line % 4) != 0) {
line = ((line / 4) + 1) * 4; // 4byte 境界にあわせる
}
for(i = 0; i < Height; i++) {
position = OffBits + line * (Height - (i + 1)); // 行の先頭位置
fseek(fp, position, SEEK_SET);
fread(buf, line, 1, fp); // 値の読み込み
}
を自分のプログラムにどう組み込めばいいのか、ご教示願えませんでしょうか?
No.1
- 回答日時:
あなたのいう「正常に変換できない」がどのようなことをさしているのかさっぱりわかりませんが, 画像の大きさを画像自身からとるようにす
ればいいのでは?この回答への補足
ご回答ありがとうございます。
>>「正常に変換できない」がどのようなことをさしているのかさっぱりわかりません
とのことですので、内容をお伝えします。
具体的には黒色への変換が途中で終わってにしまいます。
赤い四角形だけ描いてある画像に対しこのプログラムを実行すると
四角の下半分だけ黒くなるのですが、上は赤のままなのです。
ペイントでキャンパスの大きさを100*100にしてから実行すると
この場合、四角はすべて黒となります。
拙い説明で申し訳ありませんが、これでお分かりいただけたでしょうか?
>>画像の大きさを画像自身からとるようにすればいいのでは?
汎用性を考え、当然その考えは持ちました。
しかしながら、画像処理に関する知識がないため、やりたくてもできないのが現状です。
よろしければ画像の大きさを画像自身から取得する方法をご教示ください
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# このプログラミング誰か教えてくれませんか 1 2022/06/02 15:27
- C言語・C++・C# プログラミングの授業の課題です 1 2023/01/17 22:15
- C言語・C++・C# バイナリファイルをコピーするのにかかる時間を測りたいのですが実行するとFatel error:gli 2 2022/11/03 01:10
- C言語・C++・C# c言語の問題の説明、各所ごとに 5 2023/07/26 11:03
- C言語・C++・C# #include <stdio.h>int main(void) { int buf[100] = 6 2022/11/01 22:45
- Excel(エクセル) VBA フォルダ見える化のコードについて 2 2023/06/19 15:04
- Chrome(クローム) おすすめのGoogle Chromeの拡張機能 スクリーンショットをを教えてください 2 2022/05/18 03:57
- Excel(エクセル) エクセル VBA For Next 繰り返しの書き方を教えてください 6 2022/09/01 14:11
- Chrome(クローム) パソコン おすすめのGoogle Chromeの拡張機能 スクリーンショットをを教えてください 1 2022/05/19 00:37
- C言語・C++・C# C言語のエラーについて 2 2022/07/11 13:56
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
なぜCSQとCIP形式ではコ...
-
c言語でのfscanfについて
-
fgets( ) の返り値は何?
-
txtファイルの文字を配列に格納
-
c言語 ファイルから数字を読み...
-
【C言語】ファイルを読み込んで...
-
日本語ファイル名のFTPについて
-
C言語 連番データの読み込み
-
C言語を用いて、csvファイル内...
-
複数ファイルの同時読み込みの...
-
ガンマ変換 C言語でプログラ...
-
lockfについて
-
構造体とファイル検索(><)
-
C言語でファイル読み書きを早く...
-
ファイルへの書込み処理が異常...
-
fgets関数の利用 c言語
-
OpenGLによる描画内容をBMP出力
-
C言語 ファイル入出力について
-
CSVファイルの内容を構造体に格...
-
C言語でファイル名を変数にした...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
c言語でのfscanfについて
-
C言語でファイル読み書きを早く...
-
fopenでファイル名に、変数を使...
-
複数ファイルの同時読み込みの...
-
fgets( ) の返り値は何?
-
テキストファイル内に対して, ...
-
ファイルへの書込み処理が異常...
-
C言語にてXMLファイルから任意...
-
ファイル出力で改行を入れたい!
-
C言語でセグメンテーションエ...
-
エラーがわかりません、、
-
ガンマ変換 C言語でプログラ...
-
自己相関関数を求めるプログラ...
-
VisualStudioでのファイルの入...
-
同時にファイル読み込み 書き込み
-
c言語 ファイルから数字を読み...
-
大量の入力ファイルを扱うとき...
-
ファイルが読み込めない・・・
-
【C言語】ファイルを読み込んで...
-
a*(1-exp(-bx))+cの近似の方法
おすすめ情報