導(dǎo)讀Adobe Photoshop,簡(jiǎn)稱“PS”,是由Adobe Systems開發(fā)和發(fā)行的圖像處理軟件。Photoshop主要處理以像素所構(gòu)成的數(shù)字圖像。使用其眾多的編修與繪圖工具,可以有效地進(jìn)行圖片... Adobe Photoshop,簡(jiǎn)稱“PS”,是由Adobe Systems開發(fā)和發(fā)行的圖像處理軟件。Photoshop主要處理以像素所構(gòu)成的數(shù)字圖像。使用其眾多的編修與繪圖工具,可以有效地進(jìn)行圖片編輯工作。ps有很多功能,在圖像、圖形、文字、視頻、出版等各方面都有涉及。 接著上一篇文章的熱度,繼續(xù)講講一些稍微簡(jiǎn)單的算法吧。本文來講講碎片算法,先貼幾個(gè)效果圖吧: 這是個(gè)破壞性的濾鏡,拿美女來說事是因?yàn)楦銏D像的人90%是男人,色色的男人。 關(guān)于碎片濾鏡的原理,網(wǎng)絡(luò)上可找到的資料為:將圖像創(chuàng)建四個(gè)相互偏移的副本,產(chǎn)生類似重影的效果。 就憑上述一句話,我們就可以動(dòng)手了。 分析:通過上述幾幅圖像的比較,特別是眼睛部位,可以看出處理的圖應(yīng)該看得出像是單眼變成了4個(gè)眼睛,因此,網(wǎng)絡(luò)上的說法可靠。 那么偏移的中心在哪里,偏移的數(shù)量又是多少呢,4個(gè)偏移,分別是往那些方向偏移呢,這些問題也很簡(jiǎn)單,可以那PS做驗(yàn)證: 具體步驟如下:打開一幅圖像,在圖像顏色比較單調(diào)的地方(比如上述美女的手臂處)填充一處2*2像素的紅色,然后復(fù)制圖層,對(duì)復(fù)制后的圖層進(jìn)行碎片濾鏡處理,并調(diào)整圖層透明度為50%,局部放大可得到如下圖像: 如此效果,則可輕易得出結(jié)論: 偏移的中心就是以每個(gè)像素為中心,4個(gè)偏移分別以中心對(duì)稱,斜45度均勻圓周布置,水平和垂直偏移各45度,偏移量4個(gè)像素。 那么如何疊加的問題應(yīng)該可以猜測(cè),是取四次偏移后累加值的平均值。 針對(duì)如此思路,我寫出如下算法: 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]; // 用于保存圖像數(shù)據(jù),(處理前后的都為他) byte[] ImageDataC = new byte[Stride * Height]; // 用于保存克隆的圖像數(shù)據(jù) int[] OffsetX = new int[] { 4, -4, -4, 4 }; // 每個(gè)點(diǎn)的偏移量 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; // 設(shè)置為字節(jié)數(shù)組的的第一個(gè)元素在內(nèi)存中的地址 BmpData.Stride = Stride; Bmp.LockBits(new Rectangle(0, 0, Bmp.Width, Bmp.Height), ImageLockMode.ReadWrite | ImageLockMode.UserInputBuffer, PixelFormat.Format24bppRgb, BmpData); Stopwatch Sw = new Stopwatch(); // 只獲取計(jì)算用時(shí) Sw.Start(); System.Buffer.BlockCopy(ImageData, 0, ImageDataC, 0, Stride * Height); // 填充克隆數(shù)據(jù) 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++) // 累積取樣點(diǎn)的取樣和 { 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,就為了四舍五入。比如如果計(jì)算結(jié)果為108.6,則取像素109更為合理 DataP[Speed + 1] = (byte)((SumG + 2) >> 2); DataP[Speed + 2] = (byte)((SumR + 2) >> 2); Speed += 3; // 跳往下一個(gè)像素 } } Sw.Stop(); this.Text = "計(jì)算用時(shí): " + Sw.ElapsedMilliseconds.ToString() + " ms"; Bmp.UnlockBits(BmpData); // 必須先解鎖,否則Invalidate失敗 } Pic.Invalidate();} 算法中,OffsetX 和 OffsetY分別為取樣點(diǎn)像素的偏移量。同樣,由于該濾鏡涉及到了領(lǐng)域操作,在處理前需要做像素備份,但這里沒有對(duì)備份數(shù)據(jù)進(jìn)行擴(kuò)展。因此,在內(nèi)部代碼里就需要對(duì)取樣點(diǎn)的坐標(biāo)進(jìn)行驗(yàn)證,看是否超過其范圍,如果超過范圍,通常在圖像濾鏡算法范圍內(nèi),有3種處理方式: (1)超過了則認(rèn)為是其最接近的邊界值,即重復(fù)邊緣像素,這部分代碼即上述貼出的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) 只計(jì)算在圖像范圍內(nèi)的像素: if (XX >= 0 && XX < Width && YY >= 0 && YY < Height) { // 累加計(jì)算 } 當(dāng)然這樣做,就必須用一個(gè)變量記錄下都做了多少次符合條件的計(jì)算。 有興趣的朋友可以自己改改代碼試一試。 上述代碼段中DataP[Speed] = (byte)((SumB+2) >> 2);要對(duì)SumB加2的原因是為了讓結(jié)果進(jìn)行四舍五入的操作,這樣才較為合理。 經(jīng)過測(cè)試,上述代碼和PS處理的效果100%的吻合。說明我們的猜測(cè)是完全正確的。 還可以對(duì)算法進(jìn)一步擴(kuò)展: 想的遠(yuǎn)一點(diǎn),為什么非的是4個(gè)重影呢,非得是45度角度呢,非得是4個(gè)像素的水平和垂直偏移呢。我給出下圖讓有興趣的讀者自己研發(fā)吧。 圖中,角度為32度,半徑為10,碎片數(shù)為7,可產(chǎn)生類似下面的效果(可用我的Imageshop進(jìn)行驗(yàn)證): 更多PhotoShop算法原理解析系列 - 像素化-碎片相關(guān)文章請(qǐng)關(guān)注PHP中文網(wǎng)! Photoshop默認(rèn)保存的文件格式,可以保留所有有圖層、色版、通道、蒙版、路徑、未柵格化文字以及圖層樣式等。 |
溫馨提示:喜歡本站的話,請(qǐng)收藏一下本站!