f8g

ラベリング

http://www.microsoft.com/japan/msdn/academic/Articles/Algorithm/03/
http://gyazo.com/dabfdc4e6cc224cbeec343c9c428a804.png
これ使用

ImageProcessing.prototype.f= function(fnc){
	return fnc(this);
};

var ip = ImageProcessing.load("img.png");

// ImageDataを使用した方が速い
ip.support.pixel = false;
ip.initPixelControl();

var labels = [];
var fil    = 0; // ラベリングする色

ip.lock()
	// 閾値処理
	.f(function(self){
		var t = self.average().average();
		//var t = (self.max().max() - self.min().min()) / 2; // 中央値

		return self.each(function(px, x, y){
			var c = px.average();
			px = new ImageProcessing.Color(c, c, c);
			self.setPixel(x, y, px.threshold(t));
		});
	})
	// ラベリング (4近傍)
	.f(function(self){
		var labelN  = 1; // label number
		var w = self.canvas.width;
		var h = self.canvas.height;

		for(var x = 0; x < w + 1; x++)
			labels.push([]);

		var setLabel = function(x, y, num){
			if(0 > x || x >= w || 0 > y || y >= h || typeof labels[x][y] != "undefined")
				return;

			// 4近傍
			var nb = [
				[x + 1, y    , num],
				[x - 1, y    , num],
				[x    , y - 1, num],
				[x    , y + 1, num]
			];

			// 4近傍をチェック
			if(self.getPixel(x, y).r == fil){
				labels[x][y] = num;

				nb.forEach(function(args){
					setLabel.apply(null, args);
				});

			}
			else
				labels[x][y] = 0;
		};

		return self.each(function(px, x, y){
			if(px.r != fil)
				labels[x][y] = 0;
			else
				setLabel(x, y, labelN++);
		});
	})
	// ラベルの番号が何故か変なので直す
	.f(function(self){
		var labelN = 1;
		var labelNs = [];

		labels.forEach(function(_, x){
			_.forEach(function(v, y){
				if(v > 0 && !labelNs[v])
					labelNs[v] = labelN++;
				labels[x][y] = labelNs[v];
			})
		})

		return self;
	})
	// 表示
	.f(function(self){
		var colors = [
			ImageProcessing.Color.fromHex(0xff0000),
			ImageProcessing.Color.fromHex(0x00ff00),
			ImageProcessing.Color.fromHex(0x0000ff),
			ImageProcessing.Color.fromHex(0xffcc00),
			ImageProcessing.Color.fromHex(0xcc00ff),
			ImageProcessing.Color.fromHex(0x00ffcc),
		];

		labels.forEach(function(_, x){
			_.forEach(function(n, y){
				if(0 < n){
					self.setPixel(x, y, colors[n % colors.length]);
				}
			});
		});

		return self;
	})
.unlock()
.update();

エッジ処理 - 閾値処理 - ラベリング
http://gyazo.com/6e89c5c3ae5c876a8d88e7e6ff2ad8a9.png
あんまり連続でラベリングする範囲が広いと「too much recursion」と言われてしまう。タイマー使うといいのかな。

自動コントラスト

画像濃度変換処理
濃度の最小値が0, 最大値が255になるようにする濃度変換。与える関数は、

var f = function(x){
	var a = 255 / (max - min);
	var b = - a * min;
	return a * x + b;
};

一般的な画像では最大値≒255、最小値≒0ということが多いので、見た目で変わってくることはほとんどない、と思う。明るさの調節と一緒に使うと効果が分かりやすい。
http://gyazo.com/80bb62e01db51c19c82100ea02265a5d.png
これ使用

ImageProcessing.Color.prototype.intensity = function(v){
	return new Color(this.r + v, this.g + v, this.b + v);
};

ImageProcessing.prototype.autoContrast = function(){
	var self = this;

	var _f = function(max, min){
		if(max >= 255 && min <= 0)
			return function(x){ return x; };

		var a = 255 / (max - min);
		var b = - a * min;

		return function(x){
			return a * x + b;
		};
	};

	var max = this.max();
	var min = this.min();

	if(max.toString() == (new ImageProcessing.Color(255, 255, 255)).toString() &&
	   min.toString() == (new ImageProcessing.Color(  0,   0,   0)).toString())
		return this;

	var f = {
		r: _f(max.r, min.r),
		g: _f(max.g, min.g),
		b: _f(max.b, min.b)
	};

	this.each(function(px, x, y){
		self.setPixel(x, y, new ImageProcessing.Color(f.r(px.r), f.g(px.g), f.b(px.b)));
	});

	return this;
};

var ip = ImageProcessing.load("img.png");
ip.lock()
	.each(function(px, x, y){
		ip.setPixel(x, y, px.intensity(50));
	})
	.autoContrast()
.update();