>  기사  >  웹 프론트엔드  >  PhotoShop 알고리즘 원리 분석 시리즈 - 픽셀화 - 조각화

PhotoShop 알고리즘 원리 분석 시리즈 - 픽셀화 - 조각화

高洛峰
高洛峰원래의
2017-02-21 09:18:171661검색

이전 기사의 인기에 이어 조금 더 간단한 알고리즘에 대해 계속 이야기해 보겠습니다.

이 기사에서는 조각화 알고리즘에 대해 먼저 설명합니다.

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

이것이 파괴적인 필터인 이유는 이미지를 만드는 사람의 90%가 남자, 변태남자이기 때문입니다.

조각 필터의 ​​원리와 관련하여 인터넷에서 사용할 수 있는 정보는 다음과 같습니다. 서로 오프셋된 이미지 사본 4개를 생성하여 고스팅과 유사한 효과를 생성합니다.

위의 문장만으로도 시작할 수 있습니다.

분석: 위의 이미지, 특히 눈을 비교하면 처리된 이미지가 단안이 4개의 눈이 된 것처럼 보여야 함을 알 수 있습니다. 따라서 위의 진술은 다음과 같습니다. 신뢰할 수 있습니다.

그렇다면 오프셋의 중심은 어디이며 오프셋 수는 얼마입니까? 이 질문도 매우 간단합니다. verify:

구체적인 단계는 다음과 같습니다. 이미지를 열고 이미지의 색상이 상대적으로 단조로운 곳(예: 위에서 언급한 아름다움의 팔) 그런 다음 레이어를 복사하고 복사된 레이어에 조각 필터를 적용한 다음 레이어 투명도를 50%로 조정하여 다음 이미지를 얻습니다. 🎜>

이 효과를 사용하면 쉽게 결론을 내릴 수 있습니다.

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

오프셋의 중심은 각 픽셀의 중심에 있고 4개의 오프셋은 픽셀을 기준으로 대칭입니다. 경사가 45도인 중앙은 원 안에 균일하게 배열되며, 가로 및 세로 오프셋은 각각 45도, 오프셋은 4픽셀입니다.

그래서 어떻게 중첩하느냐는 질문을 짐작할 수 있는데, 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는 각각 샘플링 포인트 픽셀의 오프셋입니다. 마찬가지로 이 필터에는 현장 작업이 포함되므로 처리하기 전에 픽셀 백업이 필요하지만 여기에서는 백업 데이터가 확장되지 않습니다. 따라서 샘플링 지점의 좌표가 범위를 초과하는지 확인하기 위해 내부 코드에서 확인해야 합니다. 범위를 초과하는 경우 일반적으로 이미지 필터 알고리즘의 범위 내에 있습니다.

(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개의 유령 이미지여야 할까요? 4여야 합니다. 픽셀의 가로 및 세로 오프셋입니다. 관심 있는 독자들이 스스로 발전할 수 있도록 아래 그림을 제공합니다.

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

사진에서 각도는 32도, 반경은 10, 조각수는 7개, 다음과 유사한 효과를 낼 수 있습니다(내 Imageshop을 사용하여 확인할 수 있습니다):

PhotoShop算法原理解析系列 - 像素化-碎片 PHP 중국어 웹사이트에 주목하세요! PhotoShop算法原理解析系列 - 像素化-碎片

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.