写真を絵画風に加工するプログラムを作ってみた。 最新版はここから。

サンプル

  • 元画像

Original

  • 白黒反転する。

SNN

アルゴリズム

           
dQ = Q - P
Q         dR = R - P
          if (dQ・dQ < dR・dR)
    P     Select Q
          else
        R Select R
  • Pを中心とし、それに対して点対称の2ピクセルを取得する。
  • PとQの距離の方が近いならQを、PとRの距離の方が近いならRを選択する。
  • これをボックス内の全てのピクセルに対して行って最後にボックスのピクセル数で割る。

C言語のソース

// Symmetric Nearest Neighbor
double delta(int rc, int gc, int bc, int r, int g, int b)
{
	return sqrt((rc-r)*(rc-r) + (gc-g)*(gc-g) + (bc-b)*(bc-b));
}
void imgp_filter_snn(uint8_t *src, int w, int h, uint8_t *o, int radius)
{
	for (int y=0; y<h; y++) {
		for (int x=0; x<w; x++) {
			int xyPos = w*y + x;
			int sumR = 0;
			int sumG = 0;
			int sumB = 0;
			int cnt = 0;
			int rc = src[xyPos*3];
			int gc = src[xyPos*3+1];
			int bc = src[xyPos*3+2];
			for (int v=-radius; v<=radius; v++) {
				for (int u=-radius; u<=radius; u++,cnt++) {
					int uvPos = w*v + u;

					int pos = xyPos + uvPos;
					if (pos<0 || pos>=w*h) continue;
					int pos2 = xyPos - uvPos;
					if (pos2<0 || pos2>=w*h) continue;

					int r1 = src[(xyPos + uvPos)*3  ];
					int g1 = src[(xyPos + uvPos)*3+1];
					int b1 = src[(xyPos + uvPos)*3+2];
					int r2 = src[(xyPos - uvPos)*3  ];
					int g2 = src[(xyPos - uvPos)*3+1];
					int b2 = src[(xyPos - uvPos)*3+2];

					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;
					}
				}
			}
			o[xyPos*3  ] = sumR/cnt;
			o[xyPos*3+1] = sumG/cnt;
			o[xyPos*3+2] = sumB/cnt;
		}
	}
}