日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪(fǎng)問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > C# >内容正文

C#

C# 中Bitmap图像处理含增强对比度的三种方法

發(fā)布時(shí)間:2023/12/18 C# 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C# 中Bitmap图像处理含增强对比度的三种方法 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

Bitmap類(lèi)

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

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


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

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

???????????????????????????????????????????????????????

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

?

/// <summary>
/// 像素點(diǎn)陣轉(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; ?// 掃描線(xiàn)的寬度 ?
? ? int offset = stride - width; ?// 顯示寬度與掃描線(xiàn)寬度的間隙 ?
? ? IntPtr iptr = bmpData.Scan0; ?// 獲取bmpData的內(nèi)存起始位置 ?
? ? int scanBytes = stride * height;// 用stride寬度,表示這是內(nèi)存區(qū)域的大小 ?
? ? 下面把原始的顯示大小字節(jié)數(shù)組轉(zhuǎn)換為內(nèi)存中實(shí)際存放的字節(jié)數(shù)組 ?
? ? int posScan = 0, posReal = 0;// 分別設(shè)置兩個(gè)位置指針,指向源數(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)位置指針移過(guò)那段“間隙” ?
? ? }
? ? 用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ù)其實(shí)就是 一個(gè)像素點(diǎn)有rgb三個(gè)值而已,道理一樣。

?

例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; ?// 掃描線(xiàn)的寬度 ?
?
int offset = stride - map.Width; ?// 顯示寬度與掃描線(xiàn)寬度的間隙 ?
?
IntPtr iptr = bmpData.Scan0; ?// 獲取bmpData的內(nèi)存起始位置 ?
?
int scanBytes = stride * map.Height;// 用stride寬度,表示這是內(nèi)存區(qū)域的大小 ?
?
下面把原始的顯示大小字節(jié)數(shù)組轉(zhuǎn)換為內(nèi)存中實(shí)際存放的字節(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ù)組中
?

這里對(duì)與bitmapdata的操作方式是ReadOnly

?

?

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

運(yùn)行時(shí)間:

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

?

?// 第一種方法:像素提取法。速度慢
? ? ? ? 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?(此博客的代碼中有錯(cuò)誤,精簡(jiǎn)代碼基于內(nèi)存處理的copy順序有問(wèn)題)

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

?

總結(jié)

以上是生活随笔為你收集整理的C# 中Bitmap图像处理含增强对比度的三种方法的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。