トップページ > 画像処理 > グレースケール(アルゴリズム編)



概要

グレースケールに変換するコードを書いてみましょう。


まずグレースケールというのは白から黒までの明暗だけで表現した色の集まりのことです。
画像の上部分が10階調、下部分が256階調のグレースケールです。
「階調」というのは色数の事だと思ってください。例えば二値化された画像は2階調ですね。


グレースケールの色は全てRGBそれぞれの値が同じになります。
例えば、
  • 0x0
  • 0x121212
  • 0x777777
  • 0xA0A0A0
  • 0xFFFFFF
は全てグレースケールの一部です。


アルゴリズム

グレースケールへの変換方法は色々とあって、ここではその中の一部だけ説明したいと思います。

色の分割
まずグレースケールへの変換の前に、ピクセル色をRGBに分割する処理を書かなければなりません。
その方法については、ARGBの設定でまとめているのでそちらの記事を参照してください。

この記事では、FrocessingのColorRGBクラスを使用します。
ライブラリを使うのが嫌なら、ARGBの設定の下のほうに置いてある自作のRGBクラスがあるのでそちらを使ってもらっても構いません。


画像の読み込み
画像処理用のテンプレートを参照してください。


単純平均法
これは単純にRとGとBを足して3で割った値を、またRとGとBに入れなおす方法です。
非常に手っ取り早い方法でかつRGBの平均を取っているので、単純平均法と呼ばれています。


private function grayscale(bd:BitmapData):BitmapData
{
	var dest:BitmapData = bd.clone();
	var color:ColorRGB = new ColorRGB();
 
	for (var y:int = 0; y < bd.height; y++)
	{
		for (var x:int = 0; x < bd.width; x++)
		{
			color.value = dest.getPixel(x, y);
			var gray:int = (color.r + color.g + color.b) / 3;
			color.r = color.g = color.b = gray;
 
			dest.setPixel(x, y, color.value);
		}
	}
 
	return dest;
}
 
全体のコードはこのようになります。


var dest:BitmapData = bd.clone();
 
グレースケールに変換する対象は、引数で渡されたBitmapDataではなく、そのBitmapDataのコピーオブジェクトにします。
BitmapData#clone()でコピーを作りましょう。


var color:ColorRGB = new ColorRGB();
 
FrocessingのColorRGBオブジェクトを作ります。


for (var y:int = 0; y < bd.height; y++)
{
	for (var x:int = 0; x < bd.width; x++)
	{
	}
}
 
二重ループを書いているのは、BitmapDataの全てのピクセルにアクセスするためです。


color.value = dest.getPixel(x, y);
 
対象ピクセルを取得しましょう。
color.rで赤、color.gで緑、color.bで青の色が取得できます。


var gray:int = (color.r + color.g + color.b) / 3;
color.r = color.g = color.b = gray;
 
単純平均法は(R + G + B) / 3なので、(color.r + color.g + color.b) / 3で平均色を取得します。
あとはその平均色をr, g, bそれぞれに戻してあげるだけです。


dest.setPixel(x, y, color.value);
 
BitmapDataの対象位置に色を書き込むのを忘れないでください。


実行すると右側のようなグレースケールになります。

NTSC系加重平均法
上の単純平均法ではRGBそれぞれの平均値でした。

しかし人間の目は緑に対する感度が強く、青に対する感度が弱いと言われています。
なので、Gの配分を多めにして、Bの配分を少なめにするという平均法が生まれました。
この事を、NTSC系加重平均法といいます。

計算方法は、
R * 0.298912 + G * 0.586611 + B * 0.114478です。
この値をRGBそれぞれに代入します。


private function grayscale(bd:BitmapData):BitmapData
{
	var dest:BitmapData = bd.clone();
	var color:ColorRGB = new ColorRGB();
 
	for (var y:int = 0; y < bd.height; y++)
	{
		for (var x:int = 0; x < bd.width; x++)
		{
			color.value = dest.getPixel(x, y);
			var gray:int = color.r * 0.298912 + color.g * 0.586611 + color.b * 0.114478;
			color.r = color.g = color.b = gray;
 
			dest.setPixel(x, y, color.value);
		}
	}
 
	return dest;
}
 
単純平均法とほとんど同じコードですね。


var gray:int = color.r * 0.298912 + color.g * 0.586611 + color.b * 0.114478;
 
違うのは平均値の生成部分だけです。


実行すると右側のようなグレースケールになります。


並べてみると違いがよく分かると思います。(上:単純平均法, 下:NTSC系加重平均法)
単純平均の方がちょっと色が濃いですね。


検証用コード

package
{
	import flash.display.Sprite;
	import flash.display.BitmapData;
	import flash.display.Bitmap;
	import flash.display.Loader;
	import flash.events.Event;
	import flash.geom.Matrix;
	import flash.net.URLRequest;
	import flash.system.LoaderContext;
	import flash.system.Security;
	import frocessing.color.ColorRGB;
 
	public class Main extends Sprite
	{
		private const WIDTH:int = 250;
		private const HEIGHT:int = 250;
 
		public function Main()
		{
			Security.loadPolicyFile("http://farm3.static.flickr.com/crossdomain.xml");
			var loader:Loader = new Loader();
			loader.contentLoaderInfo.addEventListener(Event.INIT, initHandler);
			loader.load(new URLRequest("http://farm3.static.flickr.com/2047/2280715132_f0a72c1088.jpg"), new LoaderContext(true)); // 読み込みたい画像URL
		}
 
		private function initHandler(event:Event):void
		{
			var loader:Loader = event.currentTarget.loader;
 
			var matrix:Matrix = new Matrix();
			matrix.scale(WIDTH / loader.width, HEIGHT / loader.height); // 設定したいサイズ / 元サイズ
 
			var bd:BitmapData = new BitmapData(WIDTH, HEIGHT); // 設定したいサイズ
			bd.draw(loader, matrix);
			addChild(new Bitmap(grayscale(bd)));
		}
 
		private function grayscale(bd:BitmapData):BitmapData
		{
			var dest:BitmapData = bd.clone();
			var color:ColorRGB = new ColorRGB();
 
			for (var y:int = 0; y < bd.height; y++)
			{
				for (var x:int = 0; x < bd.width; x++)
				{
					color.value = dest.getPixel(x, y);
					var gray:int = color.r * 0.298912 + color.g * 0.586611 + color.b * 0.114478;
					color.r = color.g = color.b = gray;
 
					dest.setPixel(x, y, color.value);
				}
			}
 
			return dest;
		}
	}
}
 

|新しいページ|検索|ページ一覧|RSS|@ウィキご利用ガイド | 管理者にお問合せ
|ログイン|
添付ファイル