質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

89.20%

C言語によるグレースケール変換ができない

受付中

回答 2

投稿

  • 評価
  • クリップ 0
  • VIEW 527

Takayou

score 15

グレースケール変換をしたいのですが,処理前と処理後で画像が変化しません.
どの部分が間違っているのか,どなたか教えてください.

グレースケール変換の処理をする関数は以下です

//グレースケール変換
void ConvertToGrey(BMP* bmp)
{
    for (int h = 0; h < bmp->Height; h++) {
        for (int w = 0; w < bmp->Width; w++) {
            unsigned char Average = '00';
            Average = (bmp->img.red[w + h * bmp->Width]
                + bmp->img.green[w + h * bmp->Width]
                + bmp->img.blue[w + h * bmp->Width]) / 3;

            bmp->img.red[w + h + bmp->Width] = Average;
            bmp->img.green[w + h + bmp->Width] = Average;
            bmp->img.blue[w + h + bmp->Width] = Average;

        }



    }
    printf("\n");
}

全体のプログラムは以下です

/*
BMPファイルに対して, 以下の処理を行う
・グレースケール変換
・エッジ検出(Prewittオペレータ, Sobelオペレータ)
・拡大,縮小,回転, 移動(線形補間法)
*/


#include<stdio.h>
#include<stdlib.h>

typedef struct {
    unsigned char *red;
    unsigned char *blue;
    unsigned char *green;
}ImageData;

typedef struct {
    unsigned char    FileHeader[14];
    unsigned int    Size;
    int                Width, Height;
    unsigned char    InfoHeader[28];
    ImageData img;
}BMP;

//BMPファイル読み込み
void ReadBmp(const char FileName[], BMP* bmp);
//画像を書き込む
void WriteBmp(const char FileName[], BMP* bmp);
//BMP構造体ののメモリ開放
void Destruct_Bmp(BMP* bmp);
//BMP構造体の情報を表示
void Show_BmpInfo(BMP* bmp);
//グレースケール変換
void ConvertToGrey(BMP* bmp);


int main() {
    BMP bmp, bmp_forGrey;

    ReadBmp("lenna.bmp", &bmp);
    ReadBmp("lenna_out.bmp", &bmp_forGrey);

    ConvertToGrey(&bmp_forGrey);

    //Show_BmpInfo(&bmp);
    Show_BmpInfo(&bmp_forGrey);

    WriteBmp("lenna_out.bmp", &bmp);
    WriteBmp("lenna_out_Grey.bmp", &bmp_forGrey);


    Destruct_Bmp(&bmp);
    Destruct_Bmp(&bmp_forGrey);

    return 0;
}


//BMPファイル読み込み
void ReadBmp(const char FileName[], BMP* bmp)
{
    FILE* fp;

    fopen_s(&fp, FileName, "rb");
    if (fp == NULL) {
        printf("Not Found : %s", FileName);
        exit(1);
    }

    //ヘッダー情報を読み込み
    fread(bmp->FileHeader, sizeof(unsigned char), 14, fp);
    fread(&bmp->Size,       sizeof(int),   1, fp);
    fread(&bmp->Width,     sizeof(int),   1, fp);
    fread(&bmp->Height,    sizeof(int),   1, fp);
    fread(bmp->InfoHeader, sizeof(unsigned char), 28, fp);


    //画像本体の読み込み
    bmp->img.red   = (unsigned char*)malloc( (bmp->Width) * (bmp->Height) * sizeof(unsigned char));
    bmp->img.blue  = (unsigned char*)malloc( (bmp->Width) * (bmp->Height) * sizeof(unsigned char));
bmp->img.green = (unsigned char*)malloc((bmp->Width) * (bmp->Height) * sizeof(unsigned char));
if (bmp->img.red == NULL) {
    printf("メモリ確保に失敗\n");
    exit(1);
}
if (bmp->img.green == NULL) {
    printf("メモリ確保に失敗\n");
    exit(1);
}
if (bmp->img.blue == NULL) {
    printf("メモリ確保に失敗\n");
    exit(1);
}
//一列4byte単位の長さでないといけないので, padding処理を行う
int stride = (bmp->Width * 3 + 3) / 4 * 4;
unsigned char padding;

for (int h = 0; h < bmp->Height; h++) {
    for (int w = 0; w < bmp->Width; w++) {
        fread(&bmp->img.red[w + h * bmp->Width], sizeof(unsigned char), 1, fp);
        fread(&bmp->img.green[w + h * bmp->Width], sizeof(unsigned char), 1, fp);
        fread(&bmp->img.blue[w + h * bmp->Width], sizeof(unsigned char), 1, fp);
    }
    for (int i = 0; i < stride - bmp->Width * 3; i++) {
        fread(&padding, sizeof(unsigned char), 1, fp);
    }
}

//読みこんだファイルを閉じる
fclose(fp);
}

//画像を書き込む
void WriteBmp(const char FileName[], BMP* bmp)
{
    FILE* fp;
    fopen_s(&fp, FileName, "wb");
    if (fp == NULL) {
        printf("Not Found : %s\n", FileName);
        exit(1);
    }

    fwrite(bmp->FileHeader, sizeof(unsigned char), 14, fp);
    fwrite(&bmp->Size, sizeof(int), 1, fp);
    fwrite(&bmp->Width, sizeof(int), 1, fp);
    fwrite(&bmp->Height, sizeof(int), 1, fp);
    fwrite(bmp->InfoHeader, sizeof(unsigned char), 28, fp);

    //一列4byte単位でなければならないので、padding処理を行う
    int stride = (bmp->Width * 3 + 3) / 4 * 4;
    unsigned char padding = '00';

    //画像本体の書き込み
    for (int h = 0; h < bmp->Height; h++) {
        for (int w = 0; w < bmp->Width; w++) {
            fwrite(&bmp->img.red[w + h * bmp->Width], sizeof(unsigned char), 1, fp);
            fwrite(&bmp->img.green[w + h * bmp->Width], sizeof(unsigned char), 1, fp);
            fwrite(&bmp->img.blue[w + h * bmp->Width], sizeof(unsigned char), 1, fp);
        }
        for (int i = 0; i < stride - bmp->Width * 3; i++) {
            fwrite(&padding, sizeof(unsigned char), 1, fp);
        }

    }

    fclose(fp);
}

//BMP構造体のメモリを解放
void Destruct_Bmp(BMP* bmp)
{
    free(bmp->img.red);
    free(bmp->img.green);
    free(bmp->img.blue);
}

void Show_BmpInfo(BMP* bmp)
{
    printf("幅  =%d\n", bmp->Width);
    printf("高さ=%d\n", bmp->Height);
    printf("大きさ = %d\n", bmp->Height * bmp->Width);

}



//グレースケール変換
void ConvertToGrey(BMP* bmp)
{
    for (int h = 0; h < bmp->Height; h++) {
        for (int w = 0; w < bmp->Width; w++) {
            unsigned char Average = '00';
            Average = (bmp->img.red[w + h * bmp->Width]
                + bmp->img.green[w + h * bmp->Width]
                + bmp->img.blue[w + h * bmp->Width]) / 3;

            bmp->img.red  [w + h + bmp->Width] = Average;
            bmp->img.green[w + h + bmp->Width] = Average;
            bmp->img.blue [w + h + bmp->Width] = Average;        
        }
    }
    printf("\n");
}
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • thkana

    2019/09/28 22:28

    質問の回答ではないのでここに書きますが、
    RGB->白黒変換では、人間の目の感度特性の事情からG*0.6+R*0.3+B*0.1ぐらいに混ぜ合わせるのが普通です。係数についてはいろいろ細かい話はありますが、ざっくりこのくらいの値にしておけば大きな破綻はないでしょう。極論、緑信号だけを白黒でみてもそんなに違和感はありません。

    キャンセル

  • yumetodo

    2019/09/28 23:06

    係数についてはITU-RからBT. 601, BT.709, BT.2020, BT.2100などで(数字が大きいほど新しい企画だが純粋な上位互換ではない)定義されています。
    https://mntone.hateblo.jp/entry/2017/04/01/023417

    キャンセル

  • thkana

    2019/09/28 23:48

    >純粋な上位互換ではない
    というか、互換性という観点はあまりないですね。PAL/SECAMとNTSCで違ったり、いわゆるハイビジョンでもちょっと変わったり、4Kだ8Kだとなったときに「これがいいだろ」的にちょこちょこ数値が変わってきた気がします。職業的映像製作に関わるのでもない限り(アナログの時代ならベクトルスコープを覗くような...)、有効数字は一桁で大体用は足りるんじゃないでしょうか。ということで「ざっくり」でしか紹介しませんでした。とりあえずRGBの平均はないだろ、ということで。

    キャンセル

回答 2

+3

更新時の添え字の計算式が間違っているのでは?w + h + bmp->Widthでなくw + h * bmp->Width

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

-1

できない、と投げてしまう前に、デバッグできる環境を整えましょう。

Windowsであれば、VisualStudio、LinuxならEclipseあたりを使えば、ソースコードの任意の行で実行を止めて、変数やメモリの内容を見ることができます
そうやって、変換関数の実行前と後のデータを見比べてみればどうでしょう

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/09/28 16:21

    Visual Studioでデバックしてデータは比較しているのですが,3チャンネルの平均が配列に代入できていない(代入前後で値が変化していない)ことはわかっているのですが,なぜそうなるのかわからず,質問させていただきました.

    キャンセル

  • 2019/09/28 16:34

    ならそこらへんのことを質問に書きましょうよ
    なにをどう調べてなにがどうなるはずがどうなったのか、を。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 89.20%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る