これまでの普通の InsideOut は、境界の半径Rより内側のピクセルについては
r = R - r'
という変形を行ってきた。 これは、外縁と中心を線形に反転させることと等価である。
上の式は
(r / R) = 1 - (r'/R)
と変形できる。 これを線形ではなく指数関数をつかって非線形変形に拡張してみる。
(r / R) = 1 - (r'/R)**n
ここで、n は累乗の指数である。実際に関数を実装するときに使用する逆変換では、
r' = R * Math.Pow( (1 - r/R), 1/n)
となる。実際にやってみよう。
元画像は既存のものを使用した。

n = 0.5

n = 1.0 (これは今までの InsideOut と同じ)

n = 1.5

n = 2.0

n = 3.0

このように、n が1より小さいときは、従来の InsideOut に比べて変換前の中心部分が重視される。
逆に1より大きい場合は、変換前の外縁部分が相対的に拡大される。
今回つくった関数部分を示す。
public static bool NLInsideOut(ref Bitmap bmp, double cx, double cy, double radius, double index, Color bkColor) { if (bmp.PixelFormat != PixelFormat.Format24bppRgb) return false; int w = bmp.Width; int h = bmp.Height; int mg = 2; // margin for interpolations if ((cx == 0) & (cy == 0)) { cx = (double)w / 2; cy = (double)h / 2; } Bitmap tmp = new Bitmap(w + mg * 2, h + mg * 2, bmp.PixelFormat); Graphics g = Graphics.FromImage(tmp); g.Clear(bkColor); g.DrawImageUnscaled(bmp, mg, mg); g.Dispose(); g = Graphics.FromImage(bmp); if (bkColor != Color.Transparent) g.Clear(bkColor); g.Dispose(); RectangleF rct = new RectangleF(-1, -1, w + 1, h + 1); double r, a, xx, yy; double rindex = 1d / index; BmpProc24 src = new BmpProc24(tmp); BmpProc24 dst = new BmpProc24(bmp); for (int y = 0; y < h; y++) for (int x = 0; x < w; x++) { r = Math.Sqrt((x - cx) * (x - cx) + (y - cy) * (y - cy)); if (r > radius) continue; r = radius * Math.Pow((1d - r / radius), rindex); a = Math.Atan2(y - cy, x - cx); // radian xx = r * Math.Cos(a) + cx; yy = r * Math.Sin(a) + cy; if (rct.Contains(new PointF((float)xx, (float)yy))) { xx = xx + mg; yy = yy + mg; ImgUtils.intBicubic(dst, src, x, y, xx, yy); } } ImgUtils.CallDispose(dst, src, tmp); return true; }