国产午夜成人免费看片无遮挡_日本免费xxxx色视频_免费人成网上在线观看_黄网址在线永久免费观看

當(dāng)前位置:雨林木風(fēng)下載站 > 圖形圖像教程 > 詳細(xì)頁(yè)面

PhotoShop算法原理解析系列 -  風(fēng)格化-搜索邊緣。

PhotoShop算法原理解析系列 - 風(fēng)格化-搜索邊緣。

更新時(shí)間:2025-09-20 文章作者:未知 信息來(lái)源:網(wǎng)絡(luò) 閱讀次數(shù):

導(dǎo)Adobe Photoshop,簡(jiǎn)稱(chēng)“PS”,是由Adobe Systems開(kāi)發(fā)和發(fā)行的圖像處理軟件。Photoshop主要處理以像素所構(gòu)成的數(shù)字圖像。使用其眾多的編修與繪圖工具,可以有效地進(jìn)行圖片...
Adobe Photoshop,簡(jiǎn)稱(chēng)“PS”,是由Adobe Systems開(kāi)發(fā)和發(fā)行的圖像處理軟件。Photoshop主要處理以像素所構(gòu)成的數(shù)字圖像。使用其眾多的編修與繪圖工具,可以有效地進(jìn)行圖片編輯工作。ps有很多功能,在圖像、圖形、文字、視頻、出版等各方面都有涉及。
之所以不寫(xiě)系列文章一、系列文章二這樣的標(biāo)題,是因?yàn)槲也恢牢夷軋?jiān)持多久。我知道我對(duì)事情的表達(dá)能力和語(yǔ)言的豐富性方面的天賦不高。而一段代碼需要我去用心的把他從基本原理--》初步實(shí)現(xiàn)--》優(yōu)化速度 等過(guò)程用文字的方式表述清楚,恐怕不是一件很容易的事情。

我所掌握的一些Photoshop中的算法,不能說(shuō)百分之一百就是正確的,但是從執(zhí)行的效果中,大的方向肯定是沒(méi)有問(wèn)題的。

目前,從別人的文章、開(kāi)源的代碼以及自己的思考中我掌握的PS的算法可能有近100個(gè)吧。如果時(shí)間容許、自身的耐心容許,我會(huì)將這些東西慢慢的整理開(kāi)來(lái),雖然在很多人看來(lái),這些算法并不具有什么研究的價(jià)值了,畢竟人家都已經(jīng)商業(yè)化了。說(shuō)的也有道理,我姑且把他作為自我欣賞和自我滿(mǎn)足的一種方式吧。

今天,我們講講查找邊緣算法。可能我說(shuō)了原理,很多人就不會(huì)看下去了,可有幾人層仔細(xì)的研究過(guò)呢。

  先貼個(gè)效果圖吧:

PhotoShop算法原理解析系列 -  風(fēng)格化---》查找邊緣。

  原理:常見(jiàn)的Sobel邊緣算子的結(jié)果進(jìn)行反色即可

為了能吸引你繼續(xù)看下去,我先給出我的代碼的執(zhí)行速度: 針對(duì)3000*4000*3的數(shù)碼圖片,處理時(shí)間300ms

何為Sobel,從百度抄幾張圖過(guò)來(lái)了并修改地址后:

PhotoShop算法原理解析系列 -  風(fēng)格化---》查找邊緣。

  對(duì)上面兩個(gè)式子不做過(guò)多解釋?zhuān)阒恍枰榔渲蠥為輸入圖像,把G作為A的輸出圖像就可以了,最后還要做一步: G=255-G,就是查找邊緣算法。

查找邊緣類(lèi)算法都有個(gè)問(wèn)題,對(duì)圖像物理邊緣處的像素如何處理,在平日的處理代碼中,很多人就是忽略四個(gè)邊緣的像素,作為專(zhuān)業(yè)的圖像處理軟件,這可是違反最基本的原則的。對(duì)邊緣進(jìn)行的單獨(dú)的代碼處理,又會(huì)給編碼帶來(lái)冗余和繁瑣的問(wèn)題。解決問(wèn)題的最簡(jiǎn)單又高效的方式就是采用哨兵邊界。

寫(xiě)多了特效類(lèi)算法的都應(yīng)該知道,除了那種對(duì)單個(gè)像素進(jìn)行處理的算法不需要對(duì)原始圖像做個(gè)備份(不一定去全局備份),那些需要領(lǐng)域信息的算法由于算法的前一步修改了一個(gè)像素,而算法的當(dāng)前步需要未修改的像素值,因此,一般這種算法都會(huì)在開(kāi)始前對(duì)原始圖像做個(gè)克隆,在計(jì)算時(shí),需要的領(lǐng)域信息從克隆的數(shù)據(jù)中讀取。如果這個(gè)克隆的過(guò)程不是完完全全的克隆,而是擴(kuò)展適當(dāng)邊界后再克隆,就有可能解決上述的邊界處理問(wèn)題。

  比如對(duì)下面的一個(gè)圖,19×14像素大小,我們的備份圖為上下左右各擴(kuò)展一個(gè)像素的大小,并用邊緣的值填充,變?yōu)?1*16大小:

PhotoShop算法原理解析系列 -  風(fēng)格化---》查找邊緣。 PhotoShop算法原理解析系列 -  風(fēng)格化---》查找邊緣。

  這樣,在計(jì)算原圖的3*3領(lǐng)域像素時(shí),從擴(kuò)展后的克隆圖對(duì)應(yīng)點(diǎn)取樣,就不會(huì)出現(xiàn)不在圖像范圍內(nèi)的問(wèn)題了,編碼中即可以少很多判斷,可讀性也加強(qiáng)了。

在計(jì)算速度方面,注意到上面的計(jì)算式G中有個(gè)開(kāi)方運(yùn)算,這是個(gè)耗時(shí)的過(guò)程,由于圖像數(shù)據(jù)的特殊性,都必須是整數(shù),可以采用查找表的方式優(yōu)化速度,這就需要考慮表的建立。

針對(duì)本文的具體問(wèn)題,我們分兩步討論,第一:針對(duì)根號(hào)下的所有可能情況建立查找表。看看GX和GY的計(jì)算公式,考慮下兩者的平方和的最大值是多少,可能要考慮一會(huì)吧。第二:就是只建立0^2到255^2范圍內(nèi)的查找表,然后確保根號(hào)下的數(shù)字不大于255^2。為什么可以這樣做,就是因?yàn)閳D像數(shù)據(jù)的最大值就是255,如果根號(hào)下的數(shù)字大于255^2,在求出開(kāi)方值后,還是需要規(guī)整為255的。因此,本算法中應(yīng)該取后者。

private void CmdFindEdgesArray_Click(object sender, EventArgs e)
{    int X, Y;    int Width, Height, Stride, StrideC, HeightC;    int Speed, SpeedOne, SpeedTwo, SpeedThree;    int BlueOne, BlueTwo, GreenOne, GreenTwo, RedOne, RedTwo;    int PowerRed, PowerGreen, PowerBlue;
    Bitmap Bmp = (Bitmap)Pic.Image;    if (Bmp.PixelFormat != PixelFormat.Format24bppRgb) throw new Exception("不支持的圖像格式.");    byte[] SqrValue = new byte[65026];    for (Y = 0; Y < 65026; Y++) SqrValue[Y] = (byte)(255 - (int)Math.Sqrt(Y));      // 計(jì)算查找表,注意已經(jīng)砸查找表里進(jìn)行了反色
    Width = Bmp.Width; Height = Bmp.Height; Stride = (int)((Bmp.Width * 3 + 3) & 0XFFFFFFFC);
    StrideC = (Width + 2) * 3; HeightC = Height + 2;                                 // 寬度和高度都擴(kuò)展2個(gè)像素

    byte[] ImageData = new byte[Stride * Height];                                    // 用于保存圖像數(shù)據(jù),(處理前后的都為他)
    byte[] ImageDataC = new byte[StrideC * HeightC];                                // 用于保存擴(kuò)展后的圖像數(shù)據(jù)

    fixed (byte* Scan0 = &ImageData[0])
    {
        BitmapData BmpData = new BitmapData();
        BmpData.Scan0 = (IntPtr)Scan0;                                              //  設(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();        for (Y = 0; Y < Height; Y++)
        {
            System.Buffer.BlockCopy(ImageData, Stride * Y, ImageDataC, StrideC * (Y + 1), 3);        // 填充擴(kuò)展圖的左側(cè)第一列像素(不包括第一個(gè)和最后一個(gè)點(diǎn))
            System.Buffer.BlockCopy(ImageData, Stride * Y + (Width - 1) * 3, ImageDataC, StrideC * (Y + 1) + (Width + 1) * 3, 3);  // 填充最右側(cè)那一列的數(shù)據(jù)
            System.Buffer.BlockCopy(ImageData, Stride * Y, ImageDataC, StrideC * (Y + 1) + 3, Width * 3);
        }
        System.Buffer.BlockCopy(ImageDataC, StrideC, ImageDataC, 0, StrideC);              //  第一行
        System.Buffer.BlockCopy(ImageDataC, (HeightC - 2) * StrideC, ImageDataC, (HeightC - 1) * StrideC, StrideC);    //  最后一行               

        for (Y = 0; Y < Height; Y++)
        {
            Speed = Y * Stride;
            SpeedOne = StrideC * Y;            for (X = 0; X < Width; X++)
            {
                SpeedTwo = SpeedOne + StrideC;          //  盡量減少計(jì)算
                SpeedThree = SpeedTwo + StrideC;        //  下面的就是嚴(yán)格的按照Sobel算字進(jìn)行計(jì)算,代碼中的*2一般會(huì)優(yōu)化為移位或者兩個(gè)Add指令的,如果你不放心,當(dāng)然可以直接改成移位
                BlueOne = ImageDataC[SpeedOne] + 2 * ImageDataC[SpeedTwo] + ImageDataC[SpeedThree] - ImageDataC[SpeedOne + 6] - 2 * ImageDataC[SpeedTwo + 6] - ImageDataC[SpeedThree + 6];
                GreenOne = ImageDataC[SpeedOne + 1] + 2 * ImageDataC[SpeedTwo + 1] + ImageDataC[SpeedThree + 1] - ImageDataC[SpeedOne + 7] - 2 * ImageDataC[SpeedTwo + 7] - ImageDataC[SpeedThree + 7];
                RedOne = ImageDataC[SpeedOne + 2] + 2 * ImageDataC[SpeedTwo + 2] + ImageDataC[SpeedThree + 2] - ImageDataC[SpeedOne + 8] - 2 * ImageDataC[SpeedTwo + 8] - ImageDataC[SpeedThree + 8];
                BlueTwo = ImageDataC[SpeedOne] + 2 * ImageDataC[SpeedOne + 3] + ImageDataC[SpeedOne + 6] - ImageDataC[SpeedThree] - 2 * ImageDataC[SpeedThree + 3] - ImageDataC[SpeedThree + 6];
                GreenTwo = ImageDataC[SpeedOne + 1] + 2 * ImageDataC[SpeedOne + 4] + ImageDataC[SpeedOne + 7] - ImageDataC[SpeedThree + 1] - 2 * ImageDataC[SpeedThree + 4] - ImageDataC[SpeedThree + 7];
                RedTwo = ImageDataC[SpeedOne + 2] + 2 * ImageDataC[SpeedOne + 5] + ImageDataC[SpeedOne + 8] - ImageDataC[SpeedThree + 2] - 2 * ImageDataC[SpeedThree + 5] - ImageDataC[SpeedThree + 8];

                PowerBlue = BlueOne * BlueOne + BlueTwo * BlueTwo;
                PowerGreen = GreenOne * GreenOne + GreenTwo * GreenTwo;
                PowerRed = RedOne * RedOne + RedTwo * RedTwo;                if (PowerBlue > 65025) PowerBlue = 65025;           //  處理掉溢出值
                if (PowerGreen > 65025) PowerGreen = 65025;                if (PowerRed > 65025) PowerRed = 65025;
                ImageData[Speed] = SqrValue[PowerBlue];             //  查表
                ImageData[Speed + 1] = SqrValue[PowerGreen];
                ImageData[Speed + 2] = SqrValue[PowerRed];

                Speed += 3;                                  // 跳往下一個(gè)像素
                SpeedOne += 3;
            }
        }
        Sw.Stop();        this.Text = "計(jì)算用時(shí): " + Sw.ElapsedMilliseconds.ToString() + " ms";

        Bmp.UnlockBits(BmpData);                         //  必須先解鎖,否則Invalidate失敗     }
    Pic.Invalidate();
}

  為簡(jiǎn)單的起見(jiàn),這里先是用的C#的一維數(shù)組實(shí)現(xiàn)的,并且計(jì)時(shí)部分未考慮圖像數(shù)據(jù)的獲取和更新, 因?yàn)檎嬲膱D像處理過(guò)程中圖像數(shù)據(jù)肯定是已經(jīng)獲得的了。

針對(duì)上述代碼,編譯為Release模式后,執(zhí)行編譯后的EXE,對(duì)于3000*4000*3的彩色圖像,耗時(shí)約480ms,如果你是在IDE的模式先運(yùn)行,記得一定要在選項(xiàng)--》調(diào)試--》常規(guī)里不勾選 在模塊加載時(shí)取消JIT優(yōu)化(僅限托管)一欄。

PhotoShop算法原理解析系列 -  風(fēng)格化---》查找邊緣。

上述代碼中的填充克隆圖數(shù)據(jù)時(shí)并沒(méi)有新建一副圖,然后再填充其中的圖像數(shù)據(jù),而是直接填充一個(gè)數(shù)組,圖像其實(shí)不就是一片連續(xù)內(nèi)存加一點(diǎn)頭信息嗎,頭信息已經(jīng)有了,所以只要一片內(nèi)存就夠了。

克隆數(shù)據(jù)的填充采用了系統(tǒng)Buffer.BlockCopy函數(shù),該函數(shù)類(lèi)似于我們以前常用CopyMemory,速度非常快。

為進(jìn)一步調(diào)高執(zhí)行速度,我們首先來(lái)看看算法的關(guān)鍵耗時(shí)部位的代碼,即for (X = 0; X < Width; X++)內(nèi)部的代碼,我們?nèi)∫恍写a的反編譯碼來(lái)看看:

 BlueOne = ImageDataC[SpeedOne] + 2 * ImageDataC[SpeedTwo] + ImageDataC[SpeedThree] - ImageDataC[SpeedOne + 6] - 2 * ImageDataC[SpeedTwo + 6] - ImageDataC[SpeedThree + 6];

00000302 cmp ebx,edi 00000304 jae 0000073C             // 數(shù)組是否越界? 0000030a movzx eax,byte ptr [esi+ebx+8]    //  將ImageDataC[SpeedOne]中的數(shù)據(jù)傳送的eax寄存器 0000030f mov dword ptr [ebp-80h],eax 00000312 mov edx,dword ptr [ebp-2Ch] 00000315 cmp edx,edi 00000317 jae 0000073C            // 數(shù)組是否越界?            0000031d movzx edx,byte ptr [esi+edx+8]   //   將ImageDataC[SpeedTwo]中的數(shù)據(jù)傳送到edx寄存器00000322 add edx,edx             // 計(jì)算2*ImageDataC[SpeedTwo]    00000324 add eax,edx             // 計(jì)算ImageDataC[SpeedOne]+2*ImageDataC[SpeedTwo],并保存在eax寄存器中           00000326 cmp ecx,edi 00000328 jae 0000073C 0000032e movzx edx,byte ptr [esi+ecx+8]   // 將ImageDataC[SpeedThree]中的數(shù)據(jù)傳送到edx寄存器00000333 mov dword ptr [ebp+FFFFFF78h],edx 00000339 add eax,edx 0000033b lea edx,[ebx+6] 0000033e cmp edx,edi 00000340 jae 0000073C 00000346 movzx edx,byte ptr [esi+edx+8] 0000034b mov dword ptr [ebp+FFFFFF7Ch],edx 00000351 sub eax,edx 00000353 mov edx,dword ptr [ebp-2Ch] 00000356 add edx,6 00000359 cmp edx,edi 0000035b jae 0000073C 00000361 movzx edx,byte ptr [esi+edx+8] 00000366 add edx,edx 00000368 sub eax,edx 0000036a lea edx,[ecx+6] 0000036d cmp edx,edi 0000036f jae 0000073C 00000375 movzx edx,byte ptr [esi+edx+8] 0000037a mov dword ptr [ebp+FFFFFF74h],edx 00000380 sub eax,edx 00000382 mov dword ptr [ebp-30h],eax

   上述匯編碼我只注釋一點(diǎn)點(diǎn),其中最0000073c 標(biāo)號(hào),我們跟蹤后返現(xiàn)是調(diào)用了另外一個(gè)函數(shù):

0000073c call 685172A4

我們看到在獲取每一個(gè)數(shù)組元素前,都必須執(zhí)行一個(gè)cmp 和 jae指令,從分析我認(rèn)為這里是做類(lèi)似于判斷數(shù)組的下標(biāo)是否越界之類(lèi)的工作的。如果我們能確保我們的算法那不會(huì)產(chǎn)生越界,這部分代碼有很用呢,不是耽誤我做正事嗎。

為此,我認(rèn)為需要在C#中直接利用指針來(lái)實(shí)現(xiàn)算法,C#中有unsafe模式,也有指針,所以很方便,而且指針的表達(dá)即可以用*,也可以用[],比如*(P+4) 和P[4]是一個(gè)意思。那么只要做很少的修改就可以將上述代碼修改為指針版。

private void CmdFindEdgesPointer_Click(object sender, EventArgs e)
    {        int X, Y;        int Width, Height, Stride, StrideC, HeightC;        int Speed, SpeedOne, SpeedTwo, SpeedThree;        int BlueOne, BlueTwo, GreenOne, GreenTwo, RedOne, RedTwo;        int PowerRed, PowerGreen, PowerBlue;
        Bitmap Bmp = (Bitmap)Pic.Image;        if (Bmp.PixelFormat != PixelFormat.Format24bppRgb) throw new Exception("不支持的圖像格式.");        byte[] SqrValue = new byte[65026];        for (Y = 0; Y < 65026; Y++) SqrValue[Y] = (byte)(255 - (int)Math.Sqrt(Y));      // 計(jì)算查找表,注意已經(jīng)砸查找表里進(jìn)行了反色
        Width = Bmp.Width; Height = Bmp.Height; Stride = (int)((Bmp.Width * 3 + 3) & 0XFFFFFFFC);
        StrideC = (Width + 2) * 3; HeightC = Height + 2;                                 // 寬度和高度都擴(kuò)展2個(gè)像素

        byte[] ImageData = new byte[Stride * Height];                                    // 用于保存圖像數(shù)據(jù),(處理前后的都為他)
        byte[] ImageDataC = new byte[StrideC * HeightC];                                 // 用于保存擴(kuò)展后的圖像數(shù)據(jù)

        fixed (byte* P = &ImageData[0], CP = &ImageDataC[0], LP = &SqrValue[0])
        {            byte* DataP = P, DataCP = CP, LutP = LP;
            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();            for (Y = 0; Y < Height; Y++)
            {
                System.Buffer.BlockCopy(ImageData, Stride * Y, ImageDataC, StrideC * (Y + 1), 3);        // 填充擴(kuò)展圖的左側(cè)第一列像素(不包括第一個(gè)和最后一個(gè)點(diǎn))
                System.Buffer.BlockCopy(ImageData, Stride * Y + (Width - 1) * 3, ImageDataC, StrideC * (Y + 1) + (Width + 1) * 3, 3);  // 填充最右側(cè)那一列的數(shù)據(jù)
                System.Buffer.BlockCopy(ImageData, Stride * Y, ImageDataC, StrideC * (Y + 1) + 3, Width * 3);
            }
            System.Buffer.BlockCopy(ImageDataC, StrideC, ImageDataC, 0, StrideC);              //  第一行
            System.Buffer.BlockCopy(ImageDataC, (HeightC - 2) * StrideC, ImageDataC, (HeightC - 1) * StrideC, StrideC);    //  最后一行               

            for (Y = 0; Y < Height; Y++)
            {
                Speed = Y * Stride;
                SpeedOne = StrideC * Y;                for (X = 0; X < Width; X++)
                {
                    SpeedTwo = SpeedOne + StrideC;          //  盡量減少計(jì)算
                    SpeedThree = SpeedTwo + StrideC;        //  下面的就是嚴(yán)格的按照Sobel算字進(jìn)行計(jì)算,代碼中的*2一般會(huì)優(yōu)化為移位或者兩個(gè)Add指令的,如果你不放心,當(dāng)然可以直接改成移位
                    BlueOne = DataCP[SpeedOne] + 2 * DataCP[SpeedTwo] + DataCP[SpeedThree] - DataCP[SpeedOne + 6] - 2 * DataCP[SpeedTwo + 6] - DataCP[SpeedThree + 6];
                    GreenOne = DataCP[SpeedOne + 1] + 2 * DataCP[SpeedTwo + 1] + DataCP[SpeedThree + 1] - DataCP[SpeedOne + 7] - 2 * DataCP[SpeedTwo + 7] - DataCP[SpeedThree + 7];
                    RedOne = DataCP[SpeedOne + 2] + 2 * DataCP[SpeedTwo + 2] + DataCP[SpeedThree + 2] - DataCP[SpeedOne + 8] - 2 * DataCP[SpeedTwo + 8] - DataCP[SpeedThree + 8];
                    BlueTwo = DataCP[SpeedOne] + 2 * DataCP[SpeedOne + 3] + DataCP[SpeedOne + 6] - DataCP[SpeedThree] - 2 * DataCP[SpeedThree + 3] - DataCP[SpeedThree + 6];
                    GreenTwo = DataCP[SpeedOne + 1] + 2 * DataCP[SpeedOne + 4] + DataCP[SpeedOne + 7] - DataCP[SpeedThree + 1] - 2 * DataCP[SpeedThree + 4] - DataCP[SpeedThree + 7];
                    RedTwo = DataCP[SpeedOne + 2] + 2 * DataCP[SpeedOne + 5] + DataCP[SpeedOne + 8] - DataCP[SpeedThree + 2] - 2 * DataCP[SpeedThree + 5] - DataCP[SpeedThree + 8];

                    PowerBlue = BlueOne * BlueOne + BlueTwo * BlueTwo;
                    PowerGreen = GreenOne * GreenOne + GreenTwo * GreenTwo;
                    PowerRed = RedOne * RedOne + RedTwo * RedTwo;                    if (PowerBlue > 65025) PowerBlue = 65025;           //  處理掉溢出值
                    if (PowerGreen > 65025) PowerGreen = 65025;                    if (PowerRed > 65025) PowerRed = 65025;

                    DataP[Speed] = LutP[PowerBlue];                     //  查表
                    DataP[Speed + 1] = LutP[PowerGreen];
                    DataP[Speed + 2] = LutP[PowerRed];

                    Speed += 3;                                         //  跳往下一個(gè)像素
                    SpeedOne += 3;
                }
            }
            Sw.Stop();            this.Text = "計(jì)算用時(shí): " + Sw.ElapsedMilliseconds.ToString() + " ms";

            Bmp.UnlockBits(BmpData);                         //  必須先解鎖,否則Invalidate失敗         }
        Pic.Invalidate();
    }

同樣的效果,同樣的圖像,計(jì)算用時(shí)330ms。

我們?cè)趤?lái)看看相同代碼的匯編碼:

BlueOne = DataCP[SpeedOne] + 2 * DataCP[SpeedTwo] + DataCP[SpeedThree] - DataCP[SpeedOne + 6] - 2 * DataCP[SpeedTwo + 6] - DataCP[SpeedThree + 6];

00000318 movzx eax,byte ptr [esi+edi] 0000031c mov dword ptr [ebp-74h],eax 0000031f movzx edx,byte ptr [esi+ebx] 00000323 add edx,edx 00000325 add eax,edx 00000327 movzx edx,byte ptr [esi+ecx] 0000032b mov dword ptr [ebp-7Ch],edx 0000032e add eax,edx 00000330 movzx edx,byte ptr [esi+edi+6] 00000335 mov dword ptr [ebp-78h],edx 00000338 sub eax,edx 0000033a movzx edx,byte ptr [esi+ebx+6] 0000033f add edx,edx 00000341 sub eax,edx 00000343 movzx edx,byte ptr [esi+ecx+6] 00000348 mov dword ptr [ebp-80h],edx 0000034b sub eax,edx 0000034d mov dword ptr [ebp-30h],eax

生產(chǎn)的匯編碼簡(jiǎn)潔,意義明確,對(duì)比下少了很多指令。當(dāng)然速度會(huì)快很多。

注意這一段代碼:

  fixed (byte* P = &ImageData[0], CP = &ImageDataC[0], LP = &SqrValue[0])
        {            byte* DataP = P, DataCP = CP, LutP = LP;

如果你把更換為:

  fixed (byte* DataP = &ImageData[0], DataCP = &ImageDataC[0], LutP = &SqrValue[0])
{

代碼的速度反而比純數(shù)組版的還慢,至于為什么,實(shí)踐為王吧,我也沒(méi)有去分析,反正我知道有這個(gè)結(jié)果。你可以參考鐵哥的一篇文章:

閑談.Net類(lèi)型之public的不public,fixed的不能fixed

當(dāng)然這個(gè)還可以進(jìn)一步做小動(dòng)作的的優(yōu)化,比如movzx eax,byte ptr [esi+edi] 這句中,esi其實(shí)就是數(shù)組的基地址,向這樣寫(xiě)DataCP[SpeedOne] ,每次都會(huì)有這個(gè)基址+偏移的計(jì)算的,如果能實(shí)時(shí)直接動(dòng)態(tài)控制一個(gè)指針變量,使他直接指向索要的位置,則少了一次加法,雖然優(yōu)化不是很明顯,基本可以達(dá)到問(wèn)中之前所提到的300ms的時(shí)間了。具體的代碼可見(jiàn)附件。

很多人可能對(duì)我這些東西不感冒,說(shuō)這些東西丟給GPU比你現(xiàn)在的.......希望這些朋友也不要過(guò)分的打擊吧,每個(gè)人都有自己的愛(ài)好,我只愛(ài)好CPU。

更多PhotoShop算法原理解析系列 - 風(fēng)格化-查找邊緣。相關(guān)文章請(qǐng)關(guān)注PHP中文網(wǎng)!



Photoshop默認(rèn)保存的文件格式,可以保留所有有圖層、色版、通道、蒙版、路徑、未柵格化文字以及圖層樣式等。

溫馨提示:喜歡本站的話(huà),請(qǐng)收藏一下本站!

本類(lèi)教程下載

系統(tǒng)下載排行

国产午夜成人免费看片无遮挡_日本免费xxxx色视频_免费人成网上在线观看_黄网址在线永久免费观看

  • <label id="pxtpz"><meter id="pxtpz"></meter></label>
      1. <span id="pxtpz"><optgroup id="pxtpz"></optgroup></span>

        综合激情成人伊人| 欧美日韩国产系列| 日本道色综合久久| 亚洲人成人一区二区在线观看| 国产不卡一区视频| 1000部国产精品成人观看| 懂色av一区二区在线播放| 最新久久zyz资源站| 色综合久久久久综合99| 一区二区三区产品免费精品久久75| 在线看国产一区二区| 日韩av不卡一区二区| 精品电影一区二区三区| 99在线精品观看| 日日欢夜夜爽一区| 国产日韩v精品一区二区| 日本韩国一区二区三区视频| 日本欧美加勒比视频| 久久―日本道色综合久久| 色悠久久久久综合欧美99| 青青青伊人色综合久久| 亚洲国产精品ⅴa在线观看| 欧美日韩高清一区二区| 国产成人在线免费| 亚洲mv在线观看| 国产精品入口麻豆原神| 制服.丝袜.亚洲.另类.中文| 成人性生交大合| 久久精品二区亚洲w码| 夜夜嗨av一区二区三区网页| 久久久久国产精品厨房| 欧美日韩国产免费| 97国产精品videossex| 激情五月婷婷综合网| 亚洲猫色日本管| 国产欧美日韩另类一区| 日韩你懂的在线播放| 欧美精品丝袜中出| 在线亚洲一区二区| 成人黄色av网站在线| 韩国精品主播一区二区在线观看 | 久久嫩草精品久久久精品 | 韩国女主播一区| 亚洲成a人片综合在线| 亚洲欧美在线另类| 久久―日本道色综合久久| 欧美人妖巨大在线| 欧美中文字幕一区二区三区亚洲| 岛国精品在线观看| 高清不卡在线观看av| 麻豆精品国产传媒mv男同| 午夜视频在线观看一区| 亚洲男人天堂av| 国产精品福利在线播放| 26uuu亚洲| 精品国产免费视频| 日韩三级伦理片妻子的秘密按摩| 在线综合视频播放| 欧美巨大另类极品videosbest| 欧美日韩亚洲国产综合| 欧美日韩一区二区三区在线看 | 日韩写真欧美这视频| 欧美色图激情小说| 91精品一区二区三区在线观看| 在线91免费看| 精品少妇一区二区三区视频免付费 | 国内外成人在线视频| 美女在线观看视频一区二区| 精品在线播放午夜| 成人精品在线视频观看| 91免费看视频| 欧美日韩国产高清一区二区三区 | 国产一区二区伦理片| 国产一区二区不卡老阿姨| 国产成人在线免费观看| 97久久久精品综合88久久| 欧洲中文字幕精品| 欧美一区二区免费| 国产清纯美女被跳蛋高潮一区二区久久w| 久久午夜老司机| 中文字幕在线一区免费| 一区二区国产盗摄色噜噜| 日韩电影在线免费观看| 国产成人在线网站| 精品视频色一区| 久久久久久久电影| 亚洲精品第1页| 麻豆国产一区二区| 97久久精品人人爽人人爽蜜臀| 欧美欧美午夜aⅴ在线观看| 精品毛片乱码1区2区3区| 日韩毛片一二三区| 蜜臀av性久久久久蜜臀av麻豆| 国产精品中文字幕欧美| 欧洲精品一区二区| 欧美国产一区二区| 视频一区二区三区在线| www.亚洲国产| 精品久久久三级丝袜| 一区二区欧美国产| 成人av在线网| 久久亚洲综合色一区二区三区| 亚洲视频你懂的| 国产制服丝袜一区| 欧美日本一区二区在线观看| 中文字幕高清一区| 精品在线一区二区三区| 欧美人动与zoxxxx乱| 伊人一区二区三区| yourporn久久国产精品| 久久男人中文字幕资源站| 丝袜美腿高跟呻吟高潮一区| 99久久精品免费看国产| 欧美激情一区二区三区全黄| 青青国产91久久久久久| 在线观看国产一区二区| 中文字幕一区二区三| 国产九九视频一区二区三区| 日韩一级完整毛片| 日韩在线一区二区三区| 日本伦理一区二区| 亚洲综合另类小说| 色哟哟一区二区在线观看| 国产精品久久久久婷婷二区次| 国产精品88888| 久久久久久97三级| 国产精品中文字幕欧美| 久久久久久日产精品| 国精产品一区一区三区mba桃花 | 久久久不卡网国产精品二区| 久久精品999| 精品久久免费看| 久久99深爱久久99精品| 日韩精品一区二区三区在线播放| 视频一区在线播放| 91精品免费观看| 麻豆91免费看| 国产日韩欧美不卡| 成人av资源站| 夜夜嗨av一区二区三区网页| 欧美艳星brazzers| 日韩国产在线一| 欧美xxxxx牲另类人与| 久久激情五月婷婷| 久久久久久亚洲综合影院红桃 | 精品一区二区三区免费播放| 日韩亚洲欧美一区| 国产91在线看| 亚洲免费色视频| 91精品国产色综合久久| 韩国成人在线视频| 中文字幕中文字幕在线一区| 91成人网在线| 精品影视av免费| 自拍偷拍欧美精品| 欧美日韩高清不卡| 国产黄色91视频| 亚洲欧美日韩在线不卡| 91精品久久久久久久91蜜桃| 国产成人午夜视频| 一级精品视频在线观看宜春院| 欧美一区二区在线视频| 粉嫩av一区二区三区粉嫩| 亚洲精品大片www| 欧美www视频| 色乱码一区二区三区88| 蜜臀av在线播放一区二区三区| 国产欧美精品一区二区色综合| 色噜噜偷拍精品综合在线| 另类综合日韩欧美亚洲| 亚洲色图制服诱惑| 久久综合九色综合欧美就去吻| 99久久99久久精品免费看蜜桃 | 亚洲国产精品久久久久秋霞影院 | 久久精品国产99久久6| 亚洲少妇中出一区| 精品国产一区二区三区av性色| 97久久超碰国产精品电影| 国内外成人在线| 日本怡春院一区二区| 亚洲六月丁香色婷婷综合久久| 精品国产髙清在线看国产毛片 | 福利电影一区二区| 日韩不卡一区二区三区| 亚洲免费在线视频| 国产精品乱人伦中文| 26uuu另类欧美亚洲曰本| 91麻豆精品国产91久久久资源速度| 成人动漫av在线| 国产在线精品一区二区三区不卡 | 欧美va在线播放| 69av一区二区三区| 欧美午夜视频网站| 色综合一区二区三区| www.亚洲免费av| 成人开心网精品视频| 高清不卡一二三区| 成人做爰69片免费看网站| 国产精品一区二区视频| 久久99精品久久久|