圖像特效---水彩畫濾鏡

水彩畫濾鏡

水彩畫濾鏡算法如下:

1,假設原始圖像爲F(x,y),灰度化得到G(x,y)

2,構建一個半徑爲Radius的正方形模板M,邊長爲2*Radius+1

3,將MF上依次遍歷每個像素,對於當前像素P(x,y)

設置一個油漆桶數N,由於圖像灰度值範圍爲0-255,因此我們油漆桶的數量N要小於255,這個油漆桶是用來盛放不同類別的像素。

3.1首先按照油漆桶數N0-255的範圍劃分爲等距的N個油漆桶,對於模板中對應的像素,我們按照其灰度值,依次將其放入相應的油漆桶中;

3.2統計N個油漆桶中的像素數目,計算像素數最多的那個油漆桶內,像素的均值Mean,這個均值RGB就是模板中心像素P(x,y)的值。

示意圖如下:


                           Fig.1 油畫濾鏡示意圖(N=8)

注意:油漆桶數N可以調節圖像平滑度,模板半徑Radius用來調節水彩畫的水彩程度。

上述算法在進行模板遍歷時,可以採用快速均值濾波算法的方法來提高效率。

代碼如下:

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

        {

            if (radius == 0)

                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)

                {

                    for (int m = -radius; m <= radius; m++)

                    {

                        for (int n = -radius; n <= radius; n++)

                        {

                            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

                {

                    for (int m = -radius; m <= radius; m++)

                    {

                        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++)

                {

                    for (int m = -radius; m <= radius; m++)

                    {

                        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;

        }

程序demo: http://www.zealfilter.com/forum.php?mod=viewthread&tid=61&extra=page%3D1

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章