欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C# Bitmap圖像處理(含增強對比度的三種方法)

 更新時間:2021年11月18日 15:33:28   作者:莫干  
本文主要介紹了C# Bitmap圖像處理(含增強對比度的三種方法),文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下

Bitmap類

Bitmap對象封裝了GDI+中的一個位圖,此位圖由圖形圖像及其屬性的像素數(shù)據(jù)組成.因此Bitmap是用于處理由像素數(shù)據(jù)定義的圖像的對象.該類的主要方法和屬性如下:

1. GetPixel方法和SetPixel方法:獲取和設(shè)置一個圖像的指定像素的顏色.
2. PixelFormat屬性:返回圖像的像素格式.
3. Palette屬性:獲取和設(shè)置圖像所使用的顏色調(diào)色板.
4. Height Width屬性:返回圖像的高度和寬度.
5. LockBits方法和UnlockBits方法:分別鎖定和解鎖系統(tǒng)內(nèi)存中的位圖像素.在基于像素點的圖像處理方法中使用LockBits和UnlockBits是一個很好的方式,這兩種方法可以使我們指定像素的范圍來控制位圖的任意一部分,從而消除了通過循環(huán)對位圖的像素逐個進行處理,每調(diào)用LockBits之后都應(yīng)該調(diào)用一次UnlockBits.

BitmapData類

BitmapData對象指定了位圖的屬性
1. Height屬性:被鎖定位圖的高度.
2. Width屬性:被鎖定位圖的寬度.
3. PixelFormat屬性:數(shù)據(jù)的實際像素格式.
4. Scan0屬性:被鎖定數(shù)組的首字節(jié)地址,如果整個圖像被鎖定,則是圖像的第一個字節(jié)地址.
5. Stride屬性:步幅,也稱為掃描寬度.

這里要重點說說Stride屬性,這個和Width有什么區(qū)別呢,可以這么說,如果你的圖片大小也就是圖片字節(jié)是4的整數(shù)倍,那么Stride與Width是相等的,否則Stride就是大于Width的最小4的整數(shù)倍。在處理過程中,Stride肯定是4的整數(shù)倍,這里是個坑啊。。。

                                                       

例1:有一個一維像素點陣數(shù)組,里面放的是每個像素點的灰度值,知道寬和高,要轉(zhuǎn)換成bitmap

/// <summary>
/// 像素點陣轉(zhuǎn)換為bitmap
/// </summary>
/// <param name="rawValues">byte[]數(shù)組</param>
/// <param name="width">圖片的寬度</param>
/// <param name="height">圖片的高度</param>
/// <returns>bitmap圖片</returns>
public static Bitmap ToGrayBitmap(byte[] rawValues, int width, int height)
{
    Bitmap bmp = new Bitmap(width, height, System.Drawing.Imaging.PixelFormat.Format8bppIndexed);
    BitmapData bmpData = bmp.LockBits(new System.Drawing.Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format8bppIndexed);
     獲取圖像參數(shù)  
    //bmpData.Stride = width;
    int stride = bmpData.Stride;  // 掃描線的寬度  
    int offset = stride - width;  // 顯示寬度與掃描線寬度的間隙  
    IntPtr iptr = bmpData.Scan0;  // 獲取bmpData的內(nèi)存起始位置  
    int scanBytes = stride * height;// 用stride寬度,表示這是內(nèi)存區(qū)域的大小  
     下面把原始的顯示大小字節(jié)數(shù)組轉(zhuǎn)換為內(nèi)存中實際存放的字節(jié)數(shù)組  
    int posScan = 0, posReal = 0;// 分別設(shè)置兩個位置指針,指向源數(shù)組和目標(biāo)數(shù)組  
    byte[] pixelValues = new byte[scanBytes];  //為目標(biāo)數(shù)組分配內(nèi)存  
    for (int x = 0; x < height; x++)
    {
         下面的循環(huán)節(jié)是模擬行掃描  
        for (int y = 0; y < width; y++)
        {
            pixelValues[posScan++] = rawValues[posReal++];
        }
        posScan += offset;  //行掃描結(jié)束,要將目標(biāo)位置指針移過那段“間隙”  
    }
     用Marshal的Copy方法,將剛才得到的內(nèi)存字節(jié)數(shù)組復(fù)制到BitmapData中  
    System.Runtime.InteropServices.Marshal.Copy(pixelValues, 0, iptr, scanBytes);
    bmp.UnlockBits(bmpData);  // 解鎖內(nèi)存區(qū)域  
     下面的代碼是為了修改生成位圖的索引表,從偽彩修改為灰度  
    ColorPalette tempPalette;
    using (Bitmap tempBmp = new Bitmap(1, 1, System.Drawing.Imaging.PixelFormat.Format8bppIndexed))
    {
        tempPalette = tempBmp.Palette;
    }
    for (int i = 0; i < 256; i++)
    {
        tempPalette.Entries[i] = System.Drawing.Color.FromArgb(i, i, i);
    }
 
    bmp.Palette = tempPalette;
 
     算法到此結(jié)束,返回結(jié)果  
    return bmp;
}

至于24位位圖數(shù)據(jù)其實就是 一個像素點有rgb三個值而已,道理一樣。

例2::根據(jù)圖片得到他的灰度數(shù)組

//8位位圖得到除去文件頭信息的一位灰度數(shù)組
 
 
BitmapData bmpData = map.LockBits(new System.Drawing.Rectangle(0, 0, map.Width, map.Height), ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format8bppIndexed);
 
 獲取圖像參數(shù)  
 
int stride = bmpData.Stride;  // 掃描線的寬度  
 
int offset = stride - map.Width;  // 顯示寬度與掃描線寬度的間隙  
 
IntPtr iptr = bmpData.Scan0;  // 獲取bmpData的內(nèi)存起始位置  
 
int scanBytes = stride * map.Height;// 用stride寬度,表示這是內(nèi)存區(qū)域的大小  
 
 下面把原始的顯示大小字節(jié)數(shù)組轉(zhuǎn)換為內(nèi)存中實際存放的字節(jié)數(shù)組  
 
mapdata = new byte[scanBytes];  //為目標(biāo)數(shù)組分配內(nèi)存
 
System.Runtime.InteropServices.Marshal.Copy(iptr, mapdata, 0, scanBytes); //copy內(nèi)存中數(shù)據(jù)到數(shù)組中

這里對與bitmapdata的操作方式是ReadOnly

下面的三個例子分別基于像素(GetPixel和SetPixel)、基于內(nèi)存、基于指針這三種方法增強圖片對比度。均測試通過

運行時間:

1)基于像素:400-600ms
2)基于內(nèi)存:17-18ms
3)基于指針:20-23ms
利用LUT,應(yīng)該可以進一步減少運行時間

 // 第一種方法:像素提取法。速度慢
        public Bitmap MethodBaseOnPixel(Bitmap bitmap,int degree)
        {
            Color curColor;
            int grayR, grayG, grayB;
 
            double Deg = (100.0 + degree) / 100.0;
            for (int i = 0; i < bitmap.Width; i++)
            {
                for (int j = 0; j < bitmap.Height; j++)
                {
                    curColor = bitmap.GetPixel(i, j);
                    grayR =Convert.ToInt32((((curColor.R / 255.0 - 0.5) * Deg + 0.5)) * 255);
                    grayG = Convert.ToInt32((((curColor.G / 255.0 - 0.5) * Deg + 0.5)) * 255);
                    grayB = Convert.ToInt32((((curColor.B / 255.0 - 0.5) * Deg + 0.5)) * 255);
                    if (grayR < 0)
                        grayR = 0;
                    else if (grayR > 255)
                        grayR = 255;
 
                    if (grayB < 0)
                        grayB = 0;
                    else if (grayB > 255)
                        grayB = 255;
 
                    if (grayG < 0)
                        grayG = 0;
                    else if (grayG > 255)
                        grayG = 255;
 
 
                    bitmap.SetPixel(i, j, Color.FromArgb(grayR, grayG, grayB));
                }
            }
 
            return bitmap;
        }
// 第二種方法:基于內(nèi)存
        public unsafe Bitmap MethodBaseOnMemory(Bitmap bitmap, int degree)
        {
            if (bitmap == null)
            {
                return null;
            }
            double Deg = (100.0 + degree) / 100.0;
 
            int width = bitmap.Width;
            int height = bitmap.Height;
 
            int length = height * 3 * width;
            byte[] RGB = new byte[length];
 
            BitmapData data = bitmap.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
 
            System.IntPtr Scan0 = data.Scan0;
            System.Runtime.InteropServices.Marshal.Copy(Scan0, RGB, 0, length);
 
            double gray = 0;
            for (int i = 0; i < RGB.Length; i += 3)
            {
                for (int j = 0; j < 3; j++)
                {
                    gray = (((RGB[i + j] / 255.0 -0.5) * Deg+0.5)) * 255.0;
                    if (gray > 255)
                        gray = 255;
 
                    if (gray < 0)
                        gray = 0;
                    RGB[i + j] = (byte) gray;
                }
            }
 
            System.Runtime.InteropServices.Marshal.Copy(RGB, 0, Scan0, length);// 此處Copy是之前Copy的逆操作
            bitmap.UnlockBits(data);
            return bitmap;
        }
    }
//第三種方法:基于指針
        public unsafe Bitmap MethodBaseOnPtr(Bitmap b, int degree)
        {
            if (b == null)
            {
                return null;
            }
            try
            {
                double num = 0.0;
                double num2 = (100.0 + degree) / 100.0;
                num2 *= num2;
                int width = b.Width;
                int height = b.Height;
                BitmapData bitmapdata = b.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
                byte* numPtr = (byte*)bitmapdata.Scan0;
 
                int offset = bitmapdata.Stride - (width * 3);
                for (int i = 0; i < height; i++)
                {
                    for (int j = 0; j < width; j++)
                    {
                        for (int k = 0; k < 3; k++)
                        {
                            num = ((((((double)numPtr[k]) / 255.0) - 0.5) * num2) + 0.5) * 255.0;
                            if (num < 0.0)
                            {
                                num = 0.0;
                            }
                            if (num > 255.0)
                            {
                                num = 255.0;
                            }
                            numPtr[k] = (byte)num;
                        }
                        numPtr += 3;
 
                    }
                    numPtr += offset;
                }
                b.UnlockBits(bitmapdata);
                return b;
            }
            catch
            {
                return b;
            }
        }

參考:

1.  http://blog.csdn.net/jiangxinyu/article/details/6222302 (此博客的代碼中有錯誤,精簡代碼基于內(nèi)存處理的copy順序有問題)

2.  http://www.pin5i.com/showtopic-20228.html  // C# 特效圖片:霧化、浮雕等。

到此這篇關(guān)于C# Bitmap圖像處理(含增強對比度的三種方法)的文章就介紹到這了,更多相關(guān)C# Bitmap圖像處理內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

您可能感興趣的文章:

相關(guān)文章

  • 使用MSScriptControl 在 C# 中讀取json數(shù)據(jù)的方法

    使用MSScriptControl 在 C# 中讀取json數(shù)據(jù)的方法

    下面小編就為大家?guī)硪黄褂肕SScriptControl 在 C# 中讀取json數(shù)據(jù)的方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-01-01
  • 深入理解C♯ 7.0中的Tuple特性

    深入理解C♯ 7.0中的Tuple特性

    這篇文章主要介紹了C#7中Tuple特性的相關(guān)資料,文中通過示例代碼介紹的非常詳細,相信對大家具有一定的參考價值,需要的朋友可以們下面來一起學(xué)習(xí)學(xué)習(xí)吧。
    2017-03-03
  • c# 日歷控件的實現(xiàn)

    c# 日歷控件的實現(xiàn)

    這篇文章主要介紹了c# 實現(xiàn)日歷的示例代碼,幫助大家更好的理解和使用c#,感興趣的朋友可以了解下
    2020-12-12
  • 在C#的類或結(jié)構(gòu)中重寫ToString方法的用法簡介

    在C#的類或結(jié)構(gòu)中重寫ToString方法的用法簡介

    這篇文章主要介紹了在C#的類或結(jié)構(gòu)中重寫ToString方法的用法簡介,需要的朋友可以參考下
    2016-01-01
  • C#開發(fā)交互式命令行應(yīng)用示例

    C#開發(fā)交互式命令行應(yīng)用示例

    這篇文章主要為大家介紹了C#開發(fā)交互式命令行應(yīng)用示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-05-05
  • C#  ADO.NET 離線查詢的實現(xiàn)示例

    C# ADO.NET 離線查詢的實現(xiàn)示例

    這篇文章主要介紹了C# ADO.NET 離線查詢的實現(xiàn)示例,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-05-05
  • unity3d實現(xiàn)七天簽到功能

    unity3d實現(xiàn)七天簽到功能

    這篇文章主要為大家詳細介紹了unity3d實現(xiàn)七天簽到功能,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-04-04
  • C#中的委托介紹

    C#中的委托介紹

    這篇文章主要介紹了C#中的委托介紹,本文講解了聲明委托的方式、匿名方法、多播委托等內(nèi)容,需要的朋友可以參考下
    2015-01-01
  • C#使用NPOI上傳excel

    C#使用NPOI上傳excel

    這篇文章主要為大家詳細介紹了C#使用NPOI上傳excel的相關(guān)資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-05-05
  • C# 將字節(jié)流轉(zhuǎn)換為圖片的實例方法

    C# 將字節(jié)流轉(zhuǎn)換為圖片的實例方法

    C# 將字節(jié)流轉(zhuǎn)換為圖片的實例方法,需要的朋友可以參考一下
    2013-03-03

最新評論