🖼️ 写真を絵画風に加工するプログラム を作ってみた!
📌 最新版はこちら(imgp_snn.c) → GitHub: slibs
🏞️ サンプル
- 🏠 元の写真
- 🎭 加工後の画像
🔍 アルゴリズムの概要
🔢 「対称な最近傍」(Symmetric Nearest Neighbor) とは?
P を中心に、その対称位置にある 2つのピクセル (Q と R) を取得
P との距離が近い方のピクセル を選択
これを画像全体のピクセルごとに適用し、最終的にボックス内のピクセル数で割る
📏 ルールはシンプル!
P を基準点として、点対称な Q と R を取得
距離が近い方のピクセルを選択
全てのピクセルで繰り返し、平均化
📊 図で表すと…
— | — | — | — | — | 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言語のソースコード
以下は、このアルゴリズムを 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;
}
}
}
🎯 まとめ
- ✅ Symmetric Nearest Neighbor を使うと、写真を絵画風に加工できる!
- ✅ P を基準に、対称な 2 つのピクセル (Q, R) を比較し、近い方を選択するだけ!
- ✅ シンプルなC言語コード で実装可能 🏗️
📌 もっと試したい? 最新版は GitHub にあるよ! 🚀