Symmetric Nearest Neighbor

すこし落ち着いてきたので久しぶりにFlashを。

snn

今回はSymmetric Nearest Neighbor (SNN)という手法を画像に適用します。
シンメトリック ニアレスト ネイバー。訳すと対称最近傍法。
画素値の差の絶対値を “距離” として、その距離が近い画素の値を選んでいきます。
対称としているのは注目画素に対して対称方向の位置にある2つの画素を参照するからです。
つまり、
1 2 3
4 5 6
7 8 9
とあって5が注目画素なら、1と9、2と8、3と7、4と6… の位置の画素を参照し、
注目画素との距離が近い方の画素の値を採用します。

メディアンフィルタやKuwaharaフィルタと同様にエッジを残したまま画像をぼかしますが、
両者より高品質な結果が得られることが多い手法で、写真が絵画っぽくなってくれます。

・ソースコード
[as]
package {
import __AS3__.vec.Vector;

import flash.display.*;

[SWF(width = “600”, height = “250”, backgroundColor = “#000000”, frameRate = “30”)]

public class SNN extends Sprite{
[Embed(source = ‘assets/picture.jpg’)]
public var SrcImg:Class;

private var src:Bitmap;
private var dst:Bitmap;
private var srcData:Vector.;
private var w:int;
private var h:int;

public function SNN() {
stage.scaleMode = “noScale”;
src = new SrcImg() as Bitmap;
w = src.width;
h = src.height;
dst = new Bitmap(new BitmapData(w, h, false));
srcData = new Vector.(w*h, true);
srcData = src.bitmapData.getVector(src.bitmapData.rect);
dst.bitmapData.setVector(dst.bitmapData.rect, filterSNN(srcData, 3));
addChild(src);
addChild(dst).x += w;
}
// Symmetric Nearest Neighbor
private function filterSNN(src:Vector., radius:int):Vector. {
var dst:Vector. = new Vector.(w*h, true);
var sumR:uint, sumG:uint, sumB:uint;
var rc:int, gc:int, bc:int, r1:int, g1:int, b1:int, r2:int, g2:int, b2:int;
var cnt:int = 0;
var xyPos:int, uvPos:int;
for (var y:int=0;y> 16 & 0xff;
gc = src[xyPos] >> 8 & 0xff;
bc = src[xyPos] & 0xff;
for (var v:int=-radius;v<=radius;v++) { for (var u:int=-radius;u<=radius;u++,cnt++) { uvPos = w*v + u; try{ r1 = src[xyPos + uvPos] >> 16 & 0xff;
g1 = src[xyPos + uvPos] >> 8 & 0xff;
b1 = src[xyPos + uvPos] & 0xff;
r2 = src[xyPos – uvPos] >> 16 & 0xff;
g2 = src[xyPos – uvPos] >> 8 & 0xff;
b2 = src[xyPos – uvPos] & 0xff;
}catch(e:RangeError) {
break;
}catch(e:ReferenceError) {
break;
}
if (delta(rc, gc, bc, r1, g1, b1) < delta(rc, gc, bc, r2, g2, b2)) { sumR += r1; sumG += g1; sumB += b1; }else { sumR += r2; sumG += g2; sumB += b2; } } } dst[xyPos] = sumR/cnt << 16 | sumG/cnt << 8 | sumB/cnt; } } return dst; } private function delta(rc:int, gc:int, bc:int, r1:int, g1:int, b1:int):Number { return Math.sqrt((rc - r1)*(rc - r1) + (gc - g1)*(gc - g1) + (bc - b1)*(bc - b1)); } } } [/as] 少し冗長ですがアルゴリズムがわかりやすいように書きました。 画像境界外を参照したときはbreakしているだけなのでそんなに品質は良くないかも。

あわせて読む:

2 Thoughts

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です