C言語

【C言語】第10章第11回:C言語での画像処理プログラム

本記事では、C言語を使用して画像処理を行うプログラムを作成します。BMP画像の読み込み、グレースケール変換、保存の基本を学びます。

0. 記事の概要

この記事を読むメリット

  • 画像処理の基礎理解:画像データの構造や編集方法を学べます。
  • 実践的なプログラム作成:画像を操作するスキルを身につけ、実用的なツール開発につなげられます。
  • 応用力の向上:学んだ技術を応用して、画像フィルタリングやエフェクトの作成が可能になります。

この記事で学べること

  • BMP画像の基本構造
  • 画像の読み込みと編集方法
  • グレースケール変換の実装

1. 画像処理プログラムの基本設計

1.1 BMP画像の基本構造

BMP画像は以下の部分で構成されています。

  • ファイルヘッダー(ファイルサイズや画像の開始位置を記録)
  • 情報ヘッダー(画像の幅、高さ、色深度などを記録)
  • ピクセルデータ(画像の各ピクセルの色情報を格納)

1.2 プログラムの機能

このプログラムでは以下の基本機能を実装します。

  • BMP画像の読み込み
  • グレースケール変換
  • 変換結果の保存

2. コード例と詳細解説

2.1 基本コード例

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

#pragma pack(1) // 構造体のパディングを無効化

typedef struct {
    unsigned short bfType;
    unsigned int bfSize;
    unsigned short bfReserved1;
    unsigned short bfReserved2;
    unsigned int bfOffBits;
} BMPFileHeader;

typedef struct {
    unsigned int biSize;
    int biWidth;
    int biHeight;
    unsigned short biPlanes;
    unsigned short biBitCount;
    unsigned int biCompression;
    unsigned int biSizeImage;
    int biXPelsPerMeter;
    int biYPelsPerMeter;
    unsigned int biClrUsed;
    unsigned int biClrImportant;
} BMPInfoHeader;

void convertToGrayscale(unsigned char *pixelData, int width, int height) {
    for (int i = 0; i < height; i++) {
        for (int j = 0; j < width * 3; j += 3) {
            unsigned char r = pixelData[i * width * 3 + j + 2];
            unsigned char g = pixelData[i * width * 3 + j + 1];
            unsigned char b = pixelData[i * width * 3 + j];
            unsigned char gray = (r + g + b) / 3;
            pixelData[i * width * 3 + j] = gray;
            pixelData[i * width * 3 + j + 1] = gray;
            pixelData[i * width * 3 + j + 2] = gray;
        }
    }
}

int main() {
    FILE *file = fopen("input.bmp", "rb");
    if (!file) {
        perror("ファイルを開けませんでした");
        return 1;
    }

    BMPFileHeader fileHeader;
    BMPInfoHeader infoHeader;

    fread(&fileHeader, sizeof(BMPFileHeader), 1, file);
    fread(&infoHeader, sizeof(BMPInfoHeader), 1, file);

    unsigned char *pixelData = malloc(infoHeader.biSizeImage);
    fseek(file, fileHeader.bfOffBits, SEEK_SET);
    fread(pixelData, 1, infoHeader.biSizeImage, file);
    fclose(file);

    convertToGrayscale(pixelData, infoHeader.biWidth, infoHeader.biHeight);

    FILE *output = fopen("output.bmp", "wb");
    if (!output) {
        perror("出力ファイルを作成できませんでした");
        return 1;
    }

    fwrite(&fileHeader, sizeof(BMPFileHeader), 1, output);
    fwrite(&infoHeader, sizeof(BMPInfoHeader), 1, output);
    fwrite(pixelData, 1, infoHeader.biSizeImage, output);

    fclose(output);
    free(pixelData);

    printf("グレースケール変換が完了しました!\\n");
    return 0;
}
動作解説
  1. 画像の読み込み:BMPファイルのヘッダー情報を読み取り、ピクセルデータをメモリに格納します。
  2. グレースケール変換:各ピクセルのRGB値を平均してグレースケール化します。
  3. 変換結果の保存:編集済みのピクセルデータを新しいBMPファイルに書き込みます。

3. 練習問題

以下の課題に挑戦して、画像処理プログラムを拡張してみましょう。

  1. 画像を反転させる機能を追加してください。
  2. 指定された領域だけをグレースケール化する機能を追加してください。
  3. 画像を回転させる機能を実装してください。

4. 練習問題の解答と解説

問1の解答例

// 画像を反転させるロジック
void invertImage(unsigned char *pixelData, int width, int height) {
    for (int i = 0; i < height; i++) {
        for (int j = 0; j < width * 3; j += 3) {
            unsigned char tempR = pixelData[i * width * 3 + j + 2];
            unsigned char tempG = pixelData[i * width * 3 + j + 1];
            unsigned char tempB = pixelData[i * width * 3 + j];
            pixelData[i * width * 3 + j + 2] = 255 - tempR;
            pixelData[i * width * 3 + j + 1] = 255 - tempG;
            pixelData[i * width * 3 + j] = 255 - tempB;
        }
    }
}

この関数では、RGB値を255から減算して各ピクセルを反転させます。

5. まとめ

本記事では、C言語を用いてBMP画像の読み込み、編集、保存を行うプログラムを作成しました。さらに高度な処理を加え、画像処理ツールを拡張してみましょう。