Запрограммировал алгоритм Алексея и Нади (так на сколько я его вообще понял, ну и творчески переосмыслил его).
Мой алгоритм - V1,
Алгоритм Алексея и Нади - V2
version=V1: N=4, R=8, time = 0.0110607 seconds, FPS = 90
version=V2: N=4, R=8, time = 0.0132383 seconds, FPS = 75
version=V1: N=6, R=12, time = 0.0163261 seconds, FPS = 61
version=V2: N=6, R=12, time = 0.0170063 seconds, FPS = 58
При одинаковых радиусах алгоритм V1 работает быстрее, однако алгоритм V2 заблюривает картинку ну очень сильно (поэтому большие радиусы ему не нужны).
Однако, я бы даже сказал, что алгоритм V2 не заблюривает, а портит картинку и ничего общего с расфокусировкой линзы не имеет. На выходе не расфокусировка линзы, а просто размазня какая-то.
// Note! Need add reference to: WindowsBase, PresentationCore, System.Xaml
namespace Blur
{
class Program
{
enum Version
{
V1,
V2
}
static Version version = Version.V1;
const int N = 6;
const int R = 2 * N;
private const int W = 640;
private const int H = 480;
private static System.Windows.Media.PixelFormat pixelFormat = System.Windows.Media.PixelFormats.Bgr24;
static void Main (string[] args)
{
byte[] a;
if (Load("input.jpg", out a))
{
byte[] tmp = new byte[a.Length];
System.Diagnostics.Stopwatch timer = new System.Diagnostics.Stopwatch();
timer.Start();
if (version == Version.V1)
{
BlurV1(a, tmp);
}
else if (version == Version.V2)
{
BlurV2(a, tmp);
a = tmp;
}
timer.Stop();
double dt = timer.Elapsed.TotalSeconds;
System.Console.WriteLine("version={0}: N={1}, R={2}, time = {3} seconds, FPS = {4}", version, N, R, dt, (int)(1.0/dt));
Save("output-" + version + "-R" + R + ".jpg", a);
System.Console.ReadLine();
}
}
public static unsafe void BlurV1 (byte[] A, byte[] B)
{
const int dy = 3*W;
const int dx = 3;
fixed (byte* a = &A[0])
{
fixed (byte* b = &B[0])
{
for (int n = 0; n < N; n++)
{
for (int y = dy; y < dy*(H-1); y+=dy)
{
for (int x = dx; x < dx*(W-1); x+=dx)
{
int offset = y + x;
b[offset+0] = (byte)((a[offset-dy+0] + a[offset+dy+0] + a[offset-dx+0] + a[offset+dx+0]) >> 2);
b[offset+1] = (byte)((a[offset-dy+1] + a[offset+dy+1] + a[offset-dx+1] + a[offset+dx+1]) >> 2);
b[offset+2] = (byte)((a[offset-dy+2] + a[offset+dy+2] + a[offset-dx+2] + a[offset+dx+2]) >> 2);
}
}
for (int y = dy; y < dy*(H-1); y+=dy)
{
for (int x = dx; x < dx*(W-1); x+=dx)
{
int offset = y + x;
a[offset+0] = (byte)((b[offset-dy+0] + b[offset+dy+0] + b[offset-dx+0] + b[offset+dx+0]) >> 2);
a[offset+1] = (byte)((b[offset-dy+1] + b[offset+dy+1] + b[offset-dx+1] + b[offset+dx+1]) >> 2);
a[offset+2] = (byte)((b[offset-dy+2] + b[offset+dy+2] + b[offset-dx+2] + b[offset+dx+2]) >> 2);
}
}
}
}
}
}
public static unsafe void BlurV2 (byte[] input, byte[] output)
{
const int dy = 3 * W;
const int dx = 3;
int area = (2 * R + 1) * (2 * R + 1);
int c0;
int c1;
int c2;
int* sum0 = stackalloc int[H];
int* sum1 = stackalloc int[H];
int* sum2 = stackalloc int[H];
fixed (byte* a = &input[0])
{
fixed (byte* b = &output[0])
{
for (int X = dx*R; X < dx*(W-R); X+=dx)
{
for (int y = R; y < (H-R); y++)
{
int Y = dy*y;
c0 = 0;
c1 = 0;
c2 = 0;
int min = Y + X - dx*R;
int max = Y + X + dx*R;
for (int offset = min; offset <= max; offset += dx)
{
c0 += a[offset + 0];
c1 += a[offset + 1];
c2 += a[offset + 2];
}
sum0[y] = c0;
sum1[y] = c1;
sum2[y] = c2;
}
c0 = 0;
c1 = 0;
c2 = 0;
for (int yy = 0; yy <= 2*R; yy++)
{
c0 += sum0[yy];
c1 += sum1[yy];
c2 += sum2[yy];
}
for (int y = R; y < (H-R); y++)
{
int offset = X + dy*y;
c0 += (sum0[y + R] - sum0[y - R]);
c1 += (sum1[y + R] - sum1[y - R]);
c2 += (sum2[y + R] - sum2[y - R]);
b[offset + 0] = (byte)(c0 / area);
b[offset + 1] = (byte)(c1 / area);
b[offset + 2] = (byte)(c2 / area);
}
}
}
}
}
public static bool Load (string fileName, out byte[] buffer)
{
buffer = null;
using (System.IO.FileStream s = new System.IO.FileStream(fileName, System.IO.FileMode.Open, System.IO.FileAccess.Read, System.IO.FileShare.Read))
{
System.Windows.Media.Imaging.BitmapDecoder d = System.Windows.Media.Imaging.BitmapDecoder.Create(s,
System.Windows.Media.Imaging.BitmapCreateOptions.PreservePixelFormat,
System.Windows.Media.Imaging.BitmapCacheOption.Default);
System.Windows.Media.Imaging.BitmapFrame f = d.Frames[0];
if (f.PixelWidth != W)
{
System.Console.WriteLine("Unexpected width={0}, expected={1}", f.PixelWidth, W);
}
else if (f.PixelHeight != H)
{
System.Console.WriteLine("Unexpected height={0}, expected={1}", f.PixelHeight, H);
}
else if (f.Format != pixelFormat)
{
System.Console.WriteLine("Unexpected pixel format={0}, expected={1}", f.Format, pixelFormat);
}
else
{
buffer = new byte[W * H * 3];
f.CopyPixels(buffer, W * 3, 0);
}
}
return (buffer != null);
}
public static void Save (string fileName, byte[] buffer)
{
System.Windows.Media.Imaging.BitmapSource bm = System.Windows.Media.Imaging.BitmapSource.Create(
W, H, 300, 300, pixelFormat, null, buffer, W * 3);
using (System.IO.FileStream s = new System.IO.FileStream(fileName, System.IO.FileMode.Create))
{
System.Windows.Media.Imaging.JpegBitmapEncoder e = new System.Windows.Media.Imaging.JpegBitmapEncoder();
e.Frames.Add(System.Windows.Media.Imaging.BitmapFrame.Create(bm));
e.Save(s);
}
}
}
}
Прилагаю картинки для сравнения