2015-09-13 09:56:21      个评论    来源：Trent1985的专栏

1，假设原始图像为F(x,y)，灰度化得到G(x,y)；

3，将M在F上依次遍历每个像素，对于当前像素P(x,y)：

3.1首先按照油漆桶数N将0-255的范围划分为等距的N个油漆桶，对于模板中对应的像素，我们按照其灰度值，依次将其放入相应的油漆桶中；

3.2统计N个油漆桶中的像素数目，计算像素数最多的那个油漆桶内，像素的均值Mean，这个均值RGB就是模板中心像素P(x,y)的值。

Fig.1 油画滤镜示意图(N=8)

private Bitmap OilpaintFilterProcess(Bitmap srcBitmap, int radius, int smooth)

{

return srcBitmap;

smooth = smooth < 1 ? 1 : smooth;

smooth = Math.Max(1, smooth);

Bitmap a = new Bitmap(srcBitmap);

int w = srcBitmap.Width;

int h = srcBitmap.Height;

if (radius > Math.Min(w, h) / 2)

radius = (int)(Math.Min(w, h) / 2 - 0.5);

System.Drawing.Imaging.BitmapData srcData = a.LockBits(new Rectangle(0, 0, w, h), System.Drawing.Imaging.ImageLockMode.ReadWrite, System.Drawing.Imaging.PixelFormat.Format32bppArgb);

IntPtr ptr = srcData.Scan0;

int bytes = h * srcData.Stride;

byte[] srcValues = new byte[bytes];

System.Runtime.InteropServices.Marshal.Copy(ptr, srcValues, 0, bytes);

byte[] tempValues = (byte[])srcValues.Clone();

int stride = srcData.Stride;

int i, j, k;

int unit = 4;

int[] gray_bt = new int[smooth];

int[] r_bt = new int[smooth];

int[] g_bt = new int[smooth];

int[] b_bt = new int[smooth];

int[] gray_bt_src = new int[smooth];

int[] r_bt_src = new int[smooth];

int[] g_bt_src = new int[smooth];

int[] b_bt_src = new int[smooth];

int r, g, b;

int gray = 0, bt_index = 0, max = 0, maxindex = 0;

i = 0;

bool frist = true;

int pos = 0;

for (j = 0; j < h; j++)

{

if (frist)

{

{

{

pos = Math.Abs(n) * unit + Math.Abs(m) * stride;

b = srcValues[pos++];

g = srcValues[pos++];

r = srcValues[pos];

gray = (b + g + r) / 3;

bt_index = gray * smooth >> 8;

gray_bt_src[bt_index]++;

b_bt_src[bt_index] += b;

g_bt_src[bt_index] += g;

r_bt_src[bt_index] += r;

}

}

Array.Copy(gray_bt_src, gray_bt, smooth);

Array.Copy(b_bt_src, b_bt, smooth);

Array.Copy(g_bt_src, g_bt, smooth);

Array.Copy(r_bt_src, r_bt, smooth);

max = 0;

maxindex = 0;

for (k = 0; k < smooth; k++)

{

if (max < gray_bt[k])

{

max = gray_bt[k];

maxindex = k;

}

}

pos = j * stride;

tempValues[pos++] = (byte)(b_bt[maxindex] / max);

tempValues[pos++] = (byte)(g_bt[maxindex] / max);

tempValues[pos] = (byte)(r_bt[maxindex] / max);

frist = false;

}

else

{

{

pos = Math.Abs(m) * unit + Math.Abs(j - radius - 1) * stride;

b = srcValues[pos++];

g = srcValues[pos++];

r = srcValues[pos];

gray = (b + g + r) / 3;

bt_index = gray * smooth >> 8;

gray_bt_src[bt_index]--;

b_bt_src[bt_index] -= b;

g_bt_src[bt_index] -= g;

r_bt_src[bt_index] -= r;

pos = Math.Abs(m) * unit + Math.Abs(j + radius) % h * stride;

b = srcValues[pos++];

g = srcValues[pos++];

r = srcValues[pos];

gray = (b + g + r) / 3;

bt_index = gray * smooth >> 8;

gray_bt_src[bt_index]++;

b_bt_src[bt_index] += b;

g_bt_src[bt_index] += g;

r_bt_src[bt_index] += r;

}

Array.Copy(gray_bt_src, gray_bt, smooth);

Array.Copy(b_bt_src, b_bt, smooth);

Array.Copy(g_bt_src, g_bt, smooth);

Array.Copy(r_bt_src, r_bt, smooth);

}

for (i = 1; i < w; i++)

{

{

pos = Math.Abs(i - radius - 1) * unit + Math.Abs(j + m) % h * stride;

b = srcValues[pos++];

g = srcValues[pos++];

r = srcValues[pos];

gray = (b + g + r) / 3;

bt_index = gray * smooth >> 8;

gray_bt[bt_index]--;

b_bt[bt_index] -= b;

g_bt[bt_index] -= g;

r_bt[bt_index] -= r;

pos = Math.Abs(i + radius) % w * unit + Math.Abs(j + m) % h * stride;

b = srcValues[pos++];

g = srcValues[pos++];

r = srcValues[pos];

gray = (b + g + r) / 3;

bt_index = gray * smooth >> 8;

gray_bt[bt_index]++;

b_bt[bt_index] += b;

g_bt[bt_index] += g;

r_bt[bt_index] += r;

}

max = 0;

maxindex = 0;

for (k = 0; k < smooth; k++)

{

if (max < gray_bt[k])

{

max = gray_bt[k];

maxindex = k;

}

}

pos = i * unit + j * stride;

tempValues[pos++] = (byte)(b_bt[maxindex] / max);

tempValues[pos++] = (byte)(g_bt[maxindex] / max);

tempValues[pos] = (byte)(r_bt[maxindex] / max);

}

}

srcValues = (byte[])tempValues.Clone();

System.Runtime.InteropServices.Marshal.Copy(srcValues, 0, ptr, bytes);

a.UnlockBits(srcData);

return a;

}