Heim  >  Artikel  >  Web-Frontend  >  Analysereihe zum Prinzip des PhotoShop-Algorithmus – Pixelierung – Fragmentierung

Analysereihe zum Prinzip des PhotoShop-Algorithmus – Pixelierung – Fragmentierung

高洛峰
高洛峰Original
2017-02-21 09:18:171661Durchsuche

Um die Beliebtheit des vorherigen Artikels fortzusetzen, sprechen wir weiter über einige etwas einfachere Algorithmen.

In diesem Artikel geht es zunächst um den Fragmentierungsalgorithmus:

PhotoShop算法原理解析系列 - 像素化-碎片 PhotoShop算法原理解析系列 - 像素化-碎片 PhotoShop算法原理解析系列 - 像素化-碎片 PhotoShop算法原理解析系列 - 像素化-碎片

Dies ist ein destruktiver Filter. Der Grund für die Verwendung schöner Frauen ist, dass 90 % der Menschen, die Bilder erstellen, Männer sind, perverse Männer.

Zum Prinzip des Fragmentfilters gibt es im Internet folgende Informationen: Erstellen Sie vier Kopien des Bildes, die zueinander versetzt sind, wodurch ein Geisterbild-ähnlicher Effekt entsteht.

Mit dem obigen Satz können wir beginnen.

Analyse: Durch den Vergleich der obigen Bilder, insbesondere der Augen, ist ersichtlich, dass das verarbeitete Bild wie ein einzelnes Auge aussehen sollte. Daher ist das Netzwerk die obige Aussage ist zuverlässig.

Wo ist also die Mitte des Versatzes und wie viele Versätze gibt es? In welche Richtungen sind die 4 Versätze auch sehr einfach? überprüfen:

Die spezifischen Schritte sind wie folgt: Öffnen Sie ein Bild und füllen Sie eine Stelle mit einer 2*2 Pixel großen roten Farbe an einer Stelle, an der die Farbe des Bildes relativ eintönig ist (z. B , kopieren Sie dann die Ebene, wenden Sie einen Fragmentfilter auf die kopierte Ebene an und stellen Sie die Ebenentransparenz auf 50 % ein, um das folgende Bild zu erhalten:

🎜> PhotoShop算法原理解析系列 - 像素化-碎片 Mit diesem Effekt können Sie leicht die Schlussfolgerung ziehen:

Die Mitte des Versatzes ist auf jedem Pixel zentriert, und die vier Versätze sind symmetrisch dazu in der Mitte, mit einer Neigung von 45 Grad, sind gleichmäßig in einem Kreis angeordnet, mit horizontalem und vertikalem Versatz von jeweils 45 Grad und einem Versatz von 4 Pixeln.

Die Frage, wie man überlagert, lässt sich also erraten, nämlich den Durchschnitt der akkumulierten Werte nach vier Offsets zu ermitteln.

Basierend auf dieser Idee habe ich den folgenden Algorithmus geschrieben:

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();}

Algorithmus: OffsetX und OffsetY sind jeweils die Offsets der Abtastpunktpixel. Da dieser Filter Feldoperationen umfasst, ist vor der Verarbeitung ebenfalls eine Pixelsicherung erforderlich, die Sicherungsdaten werden hier jedoch nicht erweitert. Daher müssen die Koordinaten des Abtastpunkts im internen Code überprüft werden, um festzustellen, ob er seinen Bereich überschreitet. Wenn er den Bereich überschreitet, liegt er normalerweise im Bereich des Bildfilteralgorithmus. Es gibt drei Verarbeitungsmethoden:

(1) Wenn er überschritten wird, wird er als sein nächster Grenzwert betrachtet, d. h. als wiederholte Kantenpixel. Dieser Teil des Codes ist der oben angegebene if...else if-Teil .

(2) Das Zurückspulen kann durch den folgenden Code beschrieben werden:

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) Zählen Sie nur Pixel innerhalb des Bildbereichs:

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

Dazu müssen Sie natürlich a verwenden Variable, um es aufzuzeichnen. Wie viele qualifizierende Berechnungen durchgeführt wurden.

Interessierte Freunde können den Code ändern und es ausprobieren.

Im obigen Codeausschnitt ist DataP[Speed] = (byte)((SumB+2) >> 2); genauer Angemessener.

Nach dem Test stimmt der obige Code zu 100 % mit dem Effekt der PS-Verarbeitung überein. Es zeigt, dass unsere Vermutung völlig richtig ist.

Sie können den Algorithmus auch weiter ausbauen: Überlegen Sie weiter, warum müssen es 4 Geisterbilder sein? muss 4 sein. Der horizontale und vertikale Versatz der Pixel. Ich stelle das Bild unten zur Verfügung, damit interessierte Leser es selbst entwickeln können.

PhotoShop算法原理解析系列 - 像素化-碎片

Im Bild beträgt der Winkel 32 Grad, der Radius 10 und die Anzahl der Fragmente 7, Dies kann einen ähnlichen Effekt wie den folgenden erzeugen (Sie können meinen Imageshop zur Überprüfung verwenden):

PhotoShop算法原理解析系列 - 像素化-碎片 Bitte achten Sie auf die chinesische PHP-Website! PhotoShop算法原理解析系列 - 像素化-碎片

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn