グレースケール変換をしたいのですが,処理前と処理後で画像が変化しません.
どの部分が間違っているのか,どなたか教えてください.
グレースケール変換の処理をする関数は以下です
C
1 2//グレースケール変換 3void ConvertToGrey(BMP* bmp) 4{ 5 for (int h = 0; h < bmp->Height; h++) { 6 for (int w = 0; w < bmp->Width; w++) { 7 unsigned char Average = '00'; 8 Average = (bmp->img.red[w + h * bmp->Width] 9 + bmp->img.green[w + h * bmp->Width] 10 + bmp->img.blue[w + h * bmp->Width]) / 3; 11 12 bmp->img.red[w + h + bmp->Width] = Average; 13 bmp->img.green[w + h + bmp->Width] = Average; 14 bmp->img.blue[w + h + bmp->Width] = Average; 15 16 } 17 18 19 20 } 21 printf("\n"); 22}
全体のプログラムは以下です
C
1/* 2BMPファイルに対して, 以下の処理を行う 3・グレースケール変換 4・エッジ検出(Prewittオペレータ, Sobelオペレータ) 5・拡大,縮小,回転, 移動(線形補間法) 6*/ 7 8 9#include<stdio.h> 10#include<stdlib.h> 11 12typedef struct { 13 unsigned char *red; 14 unsigned char *blue; 15 unsigned char *green; 16}ImageData; 17 18typedef struct { 19 unsigned char FileHeader[14]; 20 unsigned int Size; 21 int Width, Height; 22 unsigned char InfoHeader[28]; 23 ImageData img; 24}BMP; 25 26//BMPファイル読み込み 27void ReadBmp(const char FileName[], BMP* bmp); 28//画像を書き込む 29void WriteBmp(const char FileName[], BMP* bmp); 30//BMP構造体ののメモリ開放 31void Destruct_Bmp(BMP* bmp); 32//BMP構造体の情報を表示 33void Show_BmpInfo(BMP* bmp); 34//グレースケール変換 35void ConvertToGrey(BMP* bmp); 36 37 38int main() { 39 BMP bmp, bmp_forGrey; 40 41 ReadBmp("lenna.bmp", &bmp); 42 ReadBmp("lenna_out.bmp", &bmp_forGrey); 43 44 ConvertToGrey(&bmp_forGrey); 45 46 //Show_BmpInfo(&bmp); 47 Show_BmpInfo(&bmp_forGrey); 48 49 WriteBmp("lenna_out.bmp", &bmp); 50 WriteBmp("lenna_out_Grey.bmp", &bmp_forGrey); 51 52 53 Destruct_Bmp(&bmp); 54 Destruct_Bmp(&bmp_forGrey); 55 56 return 0; 57} 58 59 60//BMPファイル読み込み 61void ReadBmp(const char FileName[], BMP* bmp) 62{ 63 FILE* fp; 64 65 fopen_s(&fp, FileName, "rb"); 66 if (fp == NULL) { 67 printf("Not Found : %s", FileName); 68 exit(1); 69 } 70 71 //ヘッダー情報を読み込み 72 fread(bmp->FileHeader, sizeof(unsigned char), 14, fp); 73 fread(&bmp->Size, sizeof(int), 1, fp); 74 fread(&bmp->Width, sizeof(int), 1, fp); 75 fread(&bmp->Height, sizeof(int), 1, fp); 76 fread(bmp->InfoHeader, sizeof(unsigned char), 28, fp); 77 78 79 //画像本体の読み込み 80 bmp->img.red = (unsigned char*)malloc( (bmp->Width) * (bmp->Height) * sizeof(unsigned char)); 81 bmp->img.blue = (unsigned char*)malloc( (bmp->Width) * (bmp->Height) * sizeof(unsigned char)); 82bmp->img.green = (unsigned char*)malloc((bmp->Width) * (bmp->Height) * sizeof(unsigned char)); 83if (bmp->img.red == NULL) { 84 printf("メモリ確保に失敗\n"); 85 exit(1); 86} 87if (bmp->img.green == NULL) { 88 printf("メモリ確保に失敗\n"); 89 exit(1); 90} 91if (bmp->img.blue == NULL) { 92 printf("メモリ確保に失敗\n"); 93 exit(1); 94} 95//一列4byte単位の長さでないといけないので, padding処理を行う 96int stride = (bmp->Width * 3 + 3) / 4 * 4; 97unsigned char padding; 98 99for (int h = 0; h < bmp->Height; h++) { 100 for (int w = 0; w < bmp->Width; w++) { 101 fread(&bmp->img.red[w + h * bmp->Width], sizeof(unsigned char), 1, fp); 102 fread(&bmp->img.green[w + h * bmp->Width], sizeof(unsigned char), 1, fp); 103 fread(&bmp->img.blue[w + h * bmp->Width], sizeof(unsigned char), 1, fp); 104 } 105 for (int i = 0; i < stride - bmp->Width * 3; i++) { 106 fread(&padding, sizeof(unsigned char), 1, fp); 107 } 108} 109 110//読みこんだファイルを閉じる 111fclose(fp); 112} 113 114//画像を書き込む 115void WriteBmp(const char FileName[], BMP* bmp) 116{ 117 FILE* fp; 118 fopen_s(&fp, FileName, "wb"); 119 if (fp == NULL) { 120 printf("Not Found : %s\n", FileName); 121 exit(1); 122 } 123 124 fwrite(bmp->FileHeader, sizeof(unsigned char), 14, fp); 125 fwrite(&bmp->Size, sizeof(int), 1, fp); 126 fwrite(&bmp->Width, sizeof(int), 1, fp); 127 fwrite(&bmp->Height, sizeof(int), 1, fp); 128 fwrite(bmp->InfoHeader, sizeof(unsigned char), 28, fp); 129 130 //一列4byte単位でなければならないので、padding処理を行う 131 int stride = (bmp->Width * 3 + 3) / 4 * 4; 132 unsigned char padding = '00'; 133 134 //画像本体の書き込み 135 for (int h = 0; h < bmp->Height; h++) { 136 for (int w = 0; w < bmp->Width; w++) { 137 fwrite(&bmp->img.red[w + h * bmp->Width], sizeof(unsigned char), 1, fp); 138 fwrite(&bmp->img.green[w + h * bmp->Width], sizeof(unsigned char), 1, fp); 139 fwrite(&bmp->img.blue[w + h * bmp->Width], sizeof(unsigned char), 1, fp); 140 } 141 for (int i = 0; i < stride - bmp->Width * 3; i++) { 142 fwrite(&padding, sizeof(unsigned char), 1, fp); 143 } 144 145 } 146 147 fclose(fp); 148} 149 150//BMP構造体のメモリを解放 151void Destruct_Bmp(BMP* bmp) 152{ 153 free(bmp->img.red); 154 free(bmp->img.green); 155 free(bmp->img.blue); 156} 157 158void Show_BmpInfo(BMP* bmp) 159{ 160 printf("幅 =%d\n", bmp->Width); 161 printf("高さ=%d\n", bmp->Height); 162 printf("大きさ = %d\n", bmp->Height * bmp->Width); 163 164} 165 166 167 168//グレースケール変換 169void ConvertToGrey(BMP* bmp) 170{ 171 for (int h = 0; h < bmp->Height; h++) { 172 for (int w = 0; w < bmp->Width; w++) { 173 unsigned char Average = '00'; 174 Average = (bmp->img.red[w + h * bmp->Width] 175 + bmp->img.green[w + h * bmp->Width] 176 + bmp->img.blue[w + h * bmp->Width]) / 3; 177 178 bmp->img.red [w + h + bmp->Width] = Average; 179 bmp->img.green[w + h + bmp->Width] = Average; 180 bmp->img.blue [w + h + bmp->Width] = Average; 181 } 182 } 183 printf("\n"); 184}
質問の回答ではないのでここに書きますが、
RGB->白黒変換では、人間の目の感度特性の事情からG*0.6+R*0.3+B*0.1ぐらいに混ぜ合わせるのが普通です。係数についてはいろいろ細かい話はありますが、ざっくりこのくらいの値にしておけば大きな破綻はないでしょう。極論、緑信号だけを白黒でみてもそんなに違和感はありません。
係数についてはITU-RからBT. 601, BT.709, BT.2020, BT.2100などで(数字が大きいほど新しい企画だが純粋な上位互換ではない)定義されています。
https://mntone.hateblo.jp/entry/2017/04/01/023417
>純粋な上位互換ではない
というか、互換性という観点はあまりないですね。PAL/SECAMとNTSCで違ったり、いわゆるハイビジョンでもちょっと変わったり、4Kだ8Kだとなったときに「これがいいだろ」的にちょこちょこ数値が変わってきた気がします。職業的映像製作に関わるのでもない限り(アナログの時代ならベクトルスコープを覗くような...)、有効数字は一桁で大体用は足りるんじゃないでしょうか。ということで「ざっくり」でしか紹介しませんでした。とりあえずRGBの平均はないだろ、ということで。