PhotoShop演算法原理解析系列 – 像素化—》片段。

來源:互聯網
上載者:User

      接著上一篇文章的熱度,繼續講講一些稍微簡單的演算法吧。

      本文來講講片段演算法,先貼幾個吧:

        
   
   

      這是個破壞性的濾鏡,拿美女來說事是因為搞映像的人90%是男人,色色的男人。

      關於片段濾鏡的原理,網路上可找到的資料為:將映像建立四個相互位移的副本,產生類似重影的效果。

      就憑上述一句話,我們就可以動手了。

      分析:通過上述幾幅映像的比較,特別是眼睛部位,可以看出處理的圖應該看得出像是單眼變成了4個眼睛,因此,網路上的說法可靠。

      那麼位移的中心在哪裡,位移的數量又是多少呢,4個位移,分別是往那些方向位移呢,這些問題也很簡單,可以那PS做驗證:

      具體步驟如下:開啟一幅映像,在映像顏色比較單調的地方(比如上述美女的手臂處)填充一處2*2像素的紅色,然後複製圖層,對複製後的圖層進行片段濾鏡處理,並調整圖層透明度為50%,局部放大可得到如像:

                                                    

       如此效果,則可輕易得出結論:

       位移的中心就是以每個像素為中心,4個位移分別以中心對稱,斜45度均勻圓周布置,水平和垂直位移各45度,位移量4個像素。

       那麼如何疊加的問題應該可以猜測,是取四次位移後累加值的平均值。

       針對如此思路,我寫出如下演算法:

private void CmdFragment_Click(object sender, EventArgs e){    int X, Y, Z, XX, YY;    int Width, Height, Stride;    int Speed, Index;    int SumR, SumG, SumB;    Bitmap Bmp = (Bitmap)Pic.Image;    if (Bmp.PixelFormat != PixelFormat.Format24bppRgb) throw new Exception("不支援的映像格式.");    Width = Bmp.Width; Height = Bmp.Height; Stride = (int)((Bmp.Width * 3 + 3) & 0XFFFFFFFC);    byte[] ImageData = new byte[Stride * Height];                                    // 用於儲存映像資料,(處理前後的都為他)    byte[] ImageDataC = new byte[Stride * Height];                                   // 用於儲存複製的映像資料    int[] OffsetX = new int[] { 4, -4, -4, 4 };                                      // 每個點的位移量    int[] OffsetY = new int[] { -4, -4, 4, 4 };    fixed (byte* P = &ImageData[0], CP = &ImageDataC[0])    {        byte* DataP = P, DataCP = CP;        BitmapData BmpData = new BitmapData();        BmpData.Scan0 = (IntPtr)DataP;                                              //  設定為位元組數組的的第一個元素在記憶體中的地址        BmpData.Stride = Stride;        Bmp.LockBits(new Rectangle(0, 0, Bmp.Width, Bmp.Height), ImageLockMode.ReadWrite | ImageLockMode.UserInputBuffer, PixelFormat.Format24bppRgb, BmpData);        Stopwatch Sw = new Stopwatch();                                             //  只擷取計算用時        Sw.Start();        System.Buffer.BlockCopy(ImageData, 0, ImageDataC, 0, Stride * Height);     //  填充複製資料                for (Y = 0; Y < Height; Y++)        {            Speed = Y * Stride;            for (X = 0; X < Width; X++)            {                SumB = 0; SumG = 0; SumR = 0;                for (Z = 0; Z < 4; Z++)                                           //  累積取樣點的取樣和                {                    XX = X + OffsetX[Z];                    YY = Y + OffsetY[Z];                    if (XX < 0)                                                    //   注意越界                        XX = 0;                    else if (XX >= Width)                        XX = Width - 1;                    if (YY < 0)                        YY = 0;                    else if (YY >= Height)                        YY = Height - 1;                    Index = YY * Stride + XX * 3;                    SumB += DataCP[Index];                    SumG += DataCP[Index + 1];                    SumR += DataCP[Index + 2];                }                DataP[Speed] = (byte)((SumB+2) >> 2);    //  求平均值(Sum+2)/4,為什麼要+2,就為了四捨五入。比如如果計算結果為108.6,則取像素109更為合理                     DataP[Speed + 1] = (byte)((SumG + 2) >> 2);                DataP[Speed + 2] = (byte)((SumR + 2) >> 2);                Speed += 3;                                                     //  跳往下一個像素            }        }        Sw.Stop();        this.Text = "計算用時: " + Sw.ElapsedMilliseconds.ToString() + " ms";        Bmp.UnlockBits(BmpData);                         //  必須先解鎖,否則Invalidate失敗     }    Pic.Invalidate();}

  演算法中,OffsetX 和 OffsetY分別為取樣點像素的位移量。同樣,由於該濾鏡涉及到了領網域作業,在處理前需要做像素備份,但這裡沒有對備份資料進行擴充。因此,在內部代碼裡就需要對取樣點的座標進行驗證,看是否超過其範圍,如果超過範圍,通常在映像濾鏡演算法範圍內,有3種處理方式:

(1)超過了則認為是其最接近的邊界值,即重複邊緣像素,這部分代碼即上述貼出的if ..... else if 部分。

(2)折回,可用如下代碼來描述:

while (XX >= Width)    XX = XX - Width;while (XX < 0)    XX = XX + Width;while (YY >= Height)    YY = YY - Height;while (YY < 0)    YY = YY + Height;

 (3) 只計算在映像範圍內的像素: 

 if (XX >= 0 && XX < Width && YY >= 0 && YY < Height) {       // 累加計算 }

      當然這樣做,就必須用一個變數記錄下都做了多少次合格計算。

      有興趣的朋友可以自己改改代碼試一試。

      上述程式碼片段中DataP[Speed] = (byte)((SumB+2) >> 2);要對SumB加2的原因是為了讓結果進行四捨五入的操作,這樣才較為合理。    

      經過測試,上述代碼和PS處理的效果100%的吻合。說明我們的猜測是完全正確的。  

      還可以對演算法進一步擴充:  想的遠一點,為什麼非的是4個重影呢,非得是45度角度呢,非得是4個像素的水平和垂直位移呢。我給出讓有興趣的讀者自己研發吧。

     

     圖中,角度為32度,半徑為10,片段數為7,可產生類似下面的效果(可用我的Imageshop進行驗證):

      
     

  完整工程:http://files.cnblogs.com/Imageshop/Fragement.rar

 ************基本上我不提供原始碼,但是我會盡量用文字把對應的演算法描述清楚或提供參考文檔**************

 *************因為靠自己的努力和實踐寫出來的效果才真正是自己的東西,人一定要靠自己*****************

 **************作者: laviewpbt   時間: 2013.7.5   聯絡QQ:  33184777  轉載請保留本行資訊**********

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.