久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

C#圖片處理常見(jiàn)方法性能比較

 _明心見(jiàn)性_ 2017-04-14

在.NET編程中,由于GDI+的出現(xiàn),,使得對(duì)于圖像的處理功能大大增強(qiáng),。在文通過(guò)一個(gè)簡(jiǎn)單黑白處理實(shí)例介紹在.NET中常見(jiàn)的圖片處理方法和原理并比較各種方法的性能。

 

黑白處理原理:彩色圖像處理成黑白效果通常有3種算法,;

(1).最大值法: 使每個(gè)像素點(diǎn)的 R, G, B 值等于原像素點(diǎn)的 RGB (顏色值) 中最大的一個(gè),;

(2).平均值法: 使用每個(gè)像素點(diǎn)的 R,G,B值等于原像素點(diǎn)的RGB值的平均值;

(3).加權(quán)平均值法: 對(duì)每個(gè)像素點(diǎn)的 R, G, B值進(jìn)行加權(quán)

自認(rèn)為第三種方法做出來(lái)的黑白效果圖像最 "真實(shí)".

 

1.GetPixel方法

 GetPixel(i,j)和SetPixel(i, j,Color)可以直接得到圖像的一個(gè)像素的Color結(jié)構(gòu),,但是處理速度比較慢.

復(fù)制代碼
復(fù)制代碼
 /// <summary>
        /// 像素法
        /// </summary>
        /// <param name="curBitmap"></param>
        private void PixelFun(Bitmap curBitmap)
        {
            int width = curBitmap.Width;
            int height = curBitmap.Height;
            for (int i = 0; i <width; i++) //這里如果用i<curBitmap.Width做循環(huán)對(duì)性能有影響
            {
                for (int j = 0; j < height; j++)
                {
                   Color  curColor = curBitmap.GetPixel(i, j);
                   int ret = (int)(curColor.R * 0.299 + curColor.G * 0.587 + curColor.B * 0.114);
                    curBitmap.SetPixel(i, j, Color.FromArgb(ret, ret, ret));
                }
            }
 }
復(fù)制代碼
復(fù)制代碼

這里提一下,,在循環(huán)次數(shù)控制時(shí)盡量不要用i<curBitmap.Width做循環(huán)條件,而是應(yīng)當(dāng)將其取出保存到一個(gè)變量中,,這樣循環(huán)時(shí)不用每次從curBitmp中取Width屬性,,從而提高性能。

盡管如此,,直接提取像素法對(duì)大像素圖片處理力不從心,,處理一張1440*900的圖片耗時(shí)2182ms.本人配置單:

處理之前截圖:


處理后:

 

可以直觀地看出用時(shí)間2056ms.多次測(cè)試有少許波動(dòng),。

2.內(nèi)存拷貝法

內(nèi)存拷貝法就是采用System.Runtime.InteropServices.Marshal.Copy將圖像數(shù)據(jù)拷貝到數(shù)組中,然后進(jìn)行處理,,這不需要直接對(duì)指針進(jìn)行操作,,不需采用unsafe,處理速度和指針處理相差不大,,處理一副1440*900的圖像大約需要34ms,。


內(nèi)存拷貝發(fā)和指針?lè)ǘ夹栌玫降囊粋€(gè)類:BitmapData

BitmapData類


BitmapData對(duì)象指定了位圖的屬性


1.       Height屬性:被鎖定位圖的高度.


2.       Width屬性:被鎖定位圖的高度.


3.       PixelFormat屬性:數(shù)據(jù)的實(shí)際像素格式.


4.       Scan0屬性:被鎖定數(shù)組的首字節(jié)地址,如果整個(gè)圖像被鎖定,,則是圖像的第一個(gè)字節(jié)地址.


5.       Stride屬性:步幅,,也稱為掃描寬度.

如上圖所示,數(shù)組的長(zhǎng)度并不一定等于圖像像素?cái)?shù)組的長(zhǎng)度,還有一部分未用區(qū)域,這涉及到位圖的數(shù)據(jù)結(jié)構(gòu),系統(tǒng)要保證每行的字節(jié)數(shù)必須為4的倍數(shù).

假設(shè)有一張圖片寬度為6,因?yàn)槭荈ormat24bppRgb格式(每像素3字節(jié),。在以下的討論中,,除非特別說(shuō)明,否則Bitmap都被認(rèn)為是24位RGB)的,,顯然,,每一行需要6*3=18個(gè)字節(jié)存儲(chǔ)。對(duì)于Bitmap就是如此,。但對(duì)于BitmapData,,雖然BitmapData.Width還是等于Bitmap.Width,但大概是出于顯示性能的考慮,,每行的實(shí)際的字節(jié)數(shù)將變成大于等于它的那個(gè)離它最近的4的整倍數(shù),,此時(shí)的實(shí)際字節(jié)數(shù)就是Stride。就此例而言,,18不是4的整倍數(shù),,而比18大的離18最近的4的倍數(shù)是20,所以這個(gè)BitmapData.Stride = 20,。顯然,,當(dāng)寬度本身就是4的倍數(shù)時(shí),BitmapData.Stride = Bitmap.Width * 3,。畫個(gè)圖可能更好理解(此圖僅代表PixelFormat= PixelFormat. Format24bppRgb時(shí)適用,,每個(gè)像素占3個(gè)字節(jié)共24位)。R,、G,、B 分別代表3個(gè)原色分量字節(jié),,BGR就表示一個(gè)像素。為了看起來(lái)方便我在每個(gè)像素之間插了個(gè)空格,,實(shí)際上是沒(méi)有的,。X表示補(bǔ)足4的倍數(shù)而自動(dòng)插入的字節(jié),。為了符合人類的閱讀習(xí)慣我分行了,其實(shí)在計(jì)算機(jī)內(nèi)存中應(yīng)該看成連續(xù)的一大段,。Scan0||-------Stride-----------||-------Width---------| ?。拢牵摇。拢牵摇,。拢牵摇,。拢牵摇。拢牵摇,。拢牵摇,。兀兀拢牵摇。拢牵摇,。拢牵摇,。拢牵摇。拢牵摇,。拢牵摇,。兀兀拢牵摇。拢牵摇,。拢牵摇。拢牵摇,。拢牵摇,。拢牵摇,。兀?則對(duì)于Format24bppRgb格式,,滿足:

BitmapData.Width*3 + 每行未使用空間(上圖的XX)=BitmapData.Stride

 

同理,,很容易推倒對(duì)于Format32bppRgb或Format32bppPArgb格式,滿足:

BitmapData.Width*4 + 每行未使用空間(上圖的XX)=BitmapData.Stride

復(fù)制代碼
復(fù)制代碼
  /// <summary>
        /// 內(nèi)存拷貝法
        /// </summary>
        /// <param name="curBitmap"></param>
        private unsafe void MemoryCopy(Bitmap curBitmap)
        {
            int width = curBitmap.Width;
            int height = curBitmap.Height;

            Rectangle rect = new Rectangle(0, 0, curBitmap.Width, curBitmap.Height);
            System.Drawing.Imaging.BitmapData bmpData = curBitmap.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite,PixelFormat.Format24bppRgb);//curBitmap.PixelFormat

            IntPtr ptr = bmpData.Scan0;
            int bytesCount = bmpData.Stride * bmpData.Height;
            byte[] arrDst = new byte[bytesCount];
            Marshal.Copy(ptr, arrDst, 0, bytesCount);
         
            for (int i = 0; i < bytesCount; i+=3)
            {
                byte colorTemp = (byte)(arrDst[i + 2] * 0.299 + arrDst[i + 1] * 0.587 + arrDst[i] * 0.114);
                arrDst[i] = arrDst[i + 1] = arrDst[i + 2] = (byte)colorTemp;

            }
            Marshal.Copy(arrDst, 0, ptr, bytesCount);
            curBitmap.UnlockBits(bmpData);
        }
復(fù)制代碼
復(fù)制代碼

 3.指針?lè)?/strong>

指針在c#中屬于unsafe操作,需要用unsafe括起來(lái)進(jìn)行處理,,速度最快,,處理一副180*180的圖像大約需要18ms。

 

采用byte* ptr = (byte*)(bmpData.Scan0); 獲取圖像數(shù)據(jù)根位置的指針,,然后用bmpData.Scan0獲取圖像的掃描寬度,,就可以進(jìn)行指針操作了。

 

復(fù)制代碼
復(fù)制代碼
    /// <summary>
        /// 指針?lè)?        /// </summary>
        /// <param name="curBitmap"></param>
        private unsafe void PointerFun(Bitmap curBitmap)
        {
            int width = curBitmap.Width; 
            int height = curBitmap.Height;

            Rectangle rect = new Rectangle(0, 0, curBitmap.Width, curBitmap.Height);
            System.Drawing.Imaging.BitmapData bmpData = curBitmap.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite,PixelFormat.Format24bppRgb );//curBitmap.PixelFormat
            byte temp = 0;
                int w = bmpData.Width;
                int h = bmpData.Height;
                byte* ptr = (byte*)(bmpData.Scan0);
                for (int i = 0; i < h; i++)
                {
                    for (int j = 0; j <w; j++)
                    {
                       temp = (byte)(0.299 * ptr[2] + 0.587 * ptr[1] + 0.114 * ptr[0]);
                        ptr[0] = ptr[1] = ptr[2] = temp;
                        ptr +=3; //Format24bppRgb格式每個(gè)像素占3字節(jié)
                    }
                    ptr += bmpData.Stride - bmpData.Width * 3 ;//每行讀取到最后“有用”數(shù)據(jù)時(shí),,跳過(guò)未使用空間XX
                }
            curBitmap.UnlockBits(bmpData);    
        }
復(fù)制代碼
復(fù)制代碼
以下是多組測(cè)試數(shù)據(jù):
 
1920*1080
1440*900
1208*800
1024*768
500*544
200*169
直接提取像素法
1705ms
1051ms
1710ms
1340ms
450ms
32ms
內(nèi)存拷貝法
54ms
33ms
26ms
20ms
7ms
0ms
指針?lè)?/pre>
28ms
17ms
14ms
10ms
3ms
0ms
 
由此可見(jiàn),,指針?lè)ㄅc直接提取像素法效率竟隔兩個(gè)數(shù)量級(jí)!

 

比較以上方法優(yōu)缺點(diǎn):

1.總體上性能 指針?lè)詮?qiáng)于內(nèi)存拷貝法,直接提取像素法性能最低,;

2.對(duì)大圖片處理指針?lè)ê蛢?nèi)存拷貝法性能提升明顯,,對(duì)小圖片都比較快;

3.直接提取像素法簡(jiǎn)單易用,,而且不必關(guān)注圖片像素格式(PixelFormat),為安全代碼,;內(nèi)存拷貝法和指針?lè)ㄈ绻桓淖冊(cè)瓐D片像素格式要針對(duì)不同的像素格式做不同的處理,且為不安全代碼,。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn),。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式,、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙,。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多