はじめに
画像処理を簡単に解説していきます。
下部にはJavaでのソースコードも載せているのでぜひご参照ください。
不定期にはなりますが、随時更新していく予定です。
チャネルとは?
一般的なデジタル画像はRGB(赤、青、緑)の3色から構成されています。
詳しく知りたい方は光の三原色で調べると良いかと思います。
要するに、ほとんどのカラー画像はRGBの3層から構成されているということです。
この各層のことを画像処理ではチャネルと呼びます。
以下の図のように3色の画像が重なっているのを想像するとよいかと思います。
なお、ここでは説明しませんが、アルファチャネルという透明度を表す層も使用することがあります。
その場合、チャネル数は4層となります。
画素値とは?
デジタル画像は複数の点(画素)の集まりで構成されています。
デジカメやスマホのカメラの性能で、何百万画素という言葉を聞いたことがあると思います。
これは、そのカメラで撮った写真は何百万もの点から構成されているという意味です。
一般に画素数(点の数)が多ければ多いほど鮮明な写真となります。
今主流のデジタル画像の画素値は各色0~255の256階調で表現されています。
チャネル数はRGBの3つなので、256^3 = 16,777,216色を表現することができます。
下の図は各画素のRGBに値が入力されている様子を示した図です。
各インデックスごと、各色ごとに値がセットされていることが理解できれば十分です。
チャネル入れ替えってどうやるの?
前節で説明した通り、各画素にはRGBの値がセットされています。
先頭から8bitずつR、G、Bの要素が並んでいるとイメージできていれば十分です
チャネル入れ替えでは、各画素値内のRGBの並び順の入れ替えをすることになります。
以下のソースコードでは、画素を順に読み込み(ラスタスキャン)ながら、RGBをBGRに並び替えることでチャネルを入れ替えています。
RGBを配列で取得できるように作成しているので、比較的理解しやすいのではないかと思います。
アルゴリズム
- 画像をラスタスキャンして、各画素に対して2から4の処理を行う。
- 画素のR, G, Bのそれぞれの値を取得する。
- RGBの値の並び順をBGRの順に並び変える。
- 画素に対して3で並び変えたBGRの値を設定する。
チャネル入れ替えの例
ソースコード
私が作成したSImageクラスを使用しています。
中身がわからなくても、直感的に読めるように実装したつもりです。
詳細を知りたい方は以下のリンクをご覧ください。
public static SImage rgb2gbr(SImage rgbImg) {
// カラー画像でない場合、そのまま返す
if (rgbImg.channel == 1)
return rgbImg.copy();
// アルファチャネルを持つ場合
if (rgbImg.channel == 4) {
var bgrImg = new SImage(rgbImg.width(), rgbImg.height(), 4);
// 画像をラスタスキャン
for (int x = 0; x < rgbImg.width(); x++)
for (int y = 0; y < rgbImg.height(); y++) {
// ARGB配列を取得
int[] argb = rgbImg.getARGB(x, y);
// 並び変えてABGR配列を取得
int[] abgr = new int[]{argb[0], argb[3], argb[2], argb[1]};
// ABGR配列を画像にセット
bgrImg.setARGB(x, y, abgr);
}
return bgrImg;
}
// カラー画像の場合
var bgrImg = new SImage(rgbImg.width(), rgbImg.height(), 3);
// 画像をラスタスキャン
for (int x = 0; x < rgbImg.width(); x++)
for (int y = 0; y < rgbImg.height(); y++) {
// RGB配列を取得
int[] rgb = rgbImg.getRGB(x, y);
// 並び変えてBGR配列を取得
int[] bgr = new int[]{rgb[2], rgb[1], rgb[0]};
// BGR配列を画像にセット
bgrImg.setRGB(x, y, bgr);
}
return bgrImg;
}