
ゆうき( @BASEBALLY15 )です^^
今日は何の用じゃ?
C言語で,画像をグレイスケールに変換したのですが,何か方法はないでしょうか?
グレイスケール化なら,数行のコードで完成するぞ!
今回は,そのコードを紹介しよう!
お願いします.

目次
C言語で画像をグレイスケール化するってどういうこと?

グレースケール(英: Gray Scaleまたはgrayscale)とは、コンピュータ上及び写真での色の表現方法の一種。デジタル画像の中でも、ピクセルの標本値に光度以外の情報が含まれていない画像のことである。グレースケールでは、二値画像と異なり、画像を光が最も強い白から最も弱い黒まで間の灰色の明暗(英語版)も含めて表現する。
引用元:Wikipedia
カラー画像の場合,赤(0~255),緑(0~255),青(0~255)の3つの色を混ぜ合わせて色を表現するのですが,グレイスケール画像は,0(黒)~255(白)の256階調で表現することが出来ます.
それでは,カラー画像をグレイスケール化する方法についてご紹介します.
画像をRAW形式に変換しよう!(準備①)
画像の形式と言えば,『.jpeg』や『.png』を思い浮かべるのではないでしょうか?
実はこの形式のままでは,画像処理を行うことが出来ません.
画像処理を行うためには,画像をRAW形式に変換しておく必要があります.
以下のサイトで,RAW形式に変換する方法をご紹介しているので,先にそちらを見て頂いた方がいいかもしれません^^
(※OpenCVを使う場合は,.jpegや.pngでも扱えます.)
標準入力関数を使えるようにしよう!(準備②)
『Visual Studio 2012以降』を使っている方は,標準入力を行うための関数を使うために,少し処理を行わなければいけません.
今から,その方法をご紹介します.
Visual Studioのヘッダーファイルを開いてください.

そして,『pch.h』をダブルクリックして,以下のコードを記述してください.
#define _CRT_SECURE_NO_WARNINGS
これで,標準入力を行うための関数(scanfやfopenなど)を使うことが出来ます^^
それでは,本題の『カラー画像をグレイスケール化する方法』についてご紹介します⤵
C言語でカラー画像をグレイスケール化しよう!(本題)
カラー画像をグレイスケール化する前に,先に以下の記事を読んでください.
この記事では,『カラー画像の読み込み』と『保存方法』について紹介されています.
今回は,カラー画像を読み込んだ後に,グレイスケール化し,最終的にグレイスケール化した画像を保存します.
その際に以下の記事で紹介されているコードを使います.
2. グレイスケール化(今回の記事で紹介)
3. グレイスケール画像の保存(以下の記事内のコードに変更を加える.)
カラー画像を読み込む前に・・・
まずは,ヘッダーファイルを記述し,読み込み用のファイルと保存用のファイルパスを用意します.
そして,画像のRGB値の配列と今回作成した関数のプロトタイプ宣言を行います.
上記の記事内の
//関数のプロトタイプを宣言する
void read_img(char *read_path, unsigned char r_in[Y_SIZE][X_SIZE], unsigned char g_in[Y_SIZE][X_SIZE], unsigned char b_in[Y_SIZE][X_SIZE]);
void save_img(char *save_path, unsigned char r[Y_SIZE][X_SIZE], unsigned char g[Y_SIZE][X_SIZE], unsigned char b[Y_SIZE][X_SIZE]);
の下に,
void gray_img(unsigned char r[Y_SIZE][X_SIZE], unsigned char g[Y_SIZE][X_SIZE], unsigned char b[Y_SIZE][X_SIZE], unsigned char img[Y_SIZE][X_SIZE]);
を追加します.
後々,グレイスケール化するための関数を作成するのですが,その関数を使うためにこの一文を記述します.
メインとなる関数を作成しておこう!
ここで紹介されているコードを書くことで,実際に画像をグレイスケール化し,保存することが出来ます.
上記の記事で,
void main(void)
{
//入力画像の読み込み
read_img(read_path, r_in, g_in, b_in);
//出力画像の保存
save_img(save_path, r_in, g_in, b_in);
}
と書いているのですが,
void main(void)
{
//入力画像の読み込み
read_img(read_path, r_in, g_in, b_in);
//グレイスケール化←追加
gray_img(r_in, g_in, b_in, gray);
//出力画像の保存
save_img(save_path, gray);
}
に変更してください.
(※グレイスケール化を行うための関数を呼び出すコードを追加する.)
それぞれの関数を作成しよう!
カラー画像を読み込むための関数は上記の記事のコードをそのまま使ってください.
グレイスケール化するための関数を作成しよう!(メイン)
グレイスケールに変換するためには,以下の式を使います.
因みに,Gray,Red,Green,Blueは各カラーの画素値を表しています.
それでは,今回の記事のメインとなる『グレイスケール化』のコードをご紹介します.
//グレイ化
void gray_img(unsigned char r[Y_SIZE][X_SIZE], unsigned char g[Y_SIZE][X_SIZE], unsigned char b[Y_SIZE][X_SIZE], unsigned char img[Y_SIZE][X_SIZE])
{
int i, j;
for (j = 0; j < Y_SIZE; j++)
{
for (i = 0; i < X_SIZE; i++)
{
img[j][i] = (unsigned char)(0.30*r[j][i] + 0.59*g[j][i] + 0.11*b[j][i]);
}
}
}
for文で画像の左上から右下までラスタ走査を行い,それぞれの画素値を『img[ j ][ i ]』に格納していきます.
ラスタ走査に関しては,以下の画像をイメージすると分かりやすいと思います.
(※白色の矢印がラスタ走査の様子です.)

グレイスケール画像を保存しよう!
上記の記事で紹介されているコードを以下のコードに変更してください.
//出力画像の保存
void save_img(char *save_path, unsigned char img[Y_SIZE][X_SIZE])
{
int i, j;
FILE *fp;
printf("どのファイルに保存しますか?-->");
scanf("%s", save_path);
//ファイルを開く
fp = fopen(save_path, "wb");
////もし,ファイルが無いときに終了させる
if (fp == NULL)
{
printf("ファイルが存在しません", save_path);
exit(-1);
}
//画像のRGB値をファイルに保存する
for (j = 0; j < Y_SIZE; j++)
{
for (i = 0; i < X_SIZE; i++)
{
fputc(img[j][i], fp);
}
}
//ファイルを閉じる
fclose(fp);
}
全体のコード
最後に,グレイスケール化のコードをまとめて載せておきます.
#include "pch.h"
#include "stdio.h"
//exitを使う際に必要
#include "stdlib.h"
//画像サイズを定義する
#define X_SIZE 640
#define Y_SIZE 480
//読み込みと保存用のファイルパスを用意
char read_path[500];
char save_path[500];
//入力のRGB値を用意
unsigned char r_in[Y_SIZE][X_SIZE], g_in[Y_SIZE][X_SIZE], b_in[Y_SIZE][X_SIZE];
//グレイ画像の出力先の配列
unsigned char gray[Y_SIZE][X_SIZE];
//関数のプロトタイプを宣言する
void read_img(char *read_path, unsigned char r_in[Y_SIZE][X_SIZE], unsigned char g_in[Y_SIZE][X_SIZE], unsigned char b_in[Y_SIZE][X_SIZE]);
void gray_img(unsigned char r[Y_SIZE][X_SIZE], unsigned char g[Y_SIZE][X_SIZE], unsigned char b[Y_SIZE][X_SIZE], unsigned char img[Y_SIZE][X_SIZE]);
void save_img(char *save_path, unsigned char img[Y_SIZE][X_SIZE]);
//メインとなる関数
void main(void)
{
//入力画像の読み込み
read_img(read_path, r_in, g_in, b_in);
//グレイスケール化
gray_img(r_in, g_in, b_in, gray);
//出力画像の保存
save_img(save_path, gray);
}
//入力画像の読み込み
void read_img(char *read_path, unsigned char r[Y_SIZE][X_SIZE], unsigned char g[Y_SIZE][X_SIZE], unsigned char b[Y_SIZE][X_SIZE])
{
int i, j;
//ファイルためのファイルを用意
printf("読み込むファイル-->");
//標準入力をバッファに格納する
scanf("%s", read_path);
FILE *fp;
//ファイルを開く
fp = fopen(read_path, "rb");
//もし,ファイルが無いときに終了させる
if (fp == NULL)
{
printf("ファイルが存在しません", read_path);
exit(-1);
}
//画像内からRGB値の取得(ラスタ走査)
for (j = 0; j < Y_SIZE; j++)
{
for (i = 0; i < X_SIZE; i++)
{
r[j][i] = fgetc(fp);
g[j][i] = fgetc(fp);
b[j][i] = fgetc(fp);
}
}
//ファイルを閉じる
fclose(fp);
}
//グレイ化
void gray_img(unsigned char r[Y_SIZE][X_SIZE], unsigned char g[Y_SIZE][X_SIZE], unsigned char b[Y_SIZE][X_SIZE], unsigned char img[Y_SIZE][X_SIZE])
{
int i, j;
for (j = 0; j < Y_SIZE; j++)
{
for (i = 0; i < X_SIZE; i++)
{
img[j][i] = (unsigned char)(0.30*r[j][i] + 0.59*g[j][i] + 0.11*b[j][i]);
}
}
}
//出力画像の保存
void save_img(char *save_path, unsigned char img[Y_SIZE][X_SIZE])
{
int i, j;
FILE *fp;
printf("どのファイルに保存しますか?-->");
scanf("%s", save_path);
//ファイルを開く
fp = fopen(save_path, "wb");
////もし,ファイルが無いときに終了させる
if (fp == NULL)
{
printf("ファイルが存在しません", save_path);
exit(-1);
}
//画像のRGB値をファイルに保存する
for (j = 0; j < Y_SIZE; j++)
{
for (i = 0; i < X_SIZE; i++)
{
fputc(img[j][i], fp);
}
}
//ファイルを閉じる
fclose(fp);
}
終わりに
今回は,カラー画像をグレイスケール化する方法についてご紹介しました.
画像のノイズを除去したりエッジを抽出するためには,グレイスケール化は欠かせないので是非マスターしてください^^
今後は,ノイズの除去やエッジの抽出方法についても紹介しようと思います.
それでは・・・
このプログラムで保存するのはrawファイルですよね?
保存したrawファイルは他の形式の画像ファイルに変換したりできるのでしょうか?教えてほしいです!
自身でプログラムを書いて,raw形式から他の形式に変換するということでしょうか?
もし,そのようでしたら,誠に申し訳ないのですが,分からないです.
ただ,raw形式で保存した画像を,ソフト等を使って他の画像形式に変換しても良いのでしたら,方法はあります.
XnViewというソフトをインストールすることで,raw形式で保存した画像をpngやjpg形式等に変換することができます.
↓
https://forest.watch.impress.co.jp/library/software/xnview/
私自身,raw形式の画像を他の形式に変換する際は,XnViewを使っています.