c#中實(shí)現(xiàn)圖片灰度化技術(shù)詳解
去年買(mǎi)了本數(shù)字圖像處理算法,一直都沒(méi)有看,前幾個(gè)星期都一直忙著工作上的活,趁這階段悠閑點(diǎn),玩一玩圖片處理,這玩意還是非常有意思的。
以前我們?cè)谧鯳eb上的用戶(hù)注冊(cè)時(shí),通常都會(huì)做一個(gè)驗(yàn)證碼,大家都知道用來(lái)防止暴力注冊(cè)的,當(dāng)然提到驗(yàn)證碼大家都知道C#里面有一個(gè)Bitmap類(lèi)專(zhuān)門(mén)用來(lái)處理圖片的,好吧,這一篇我們從最簡(jiǎn)單的“圖片灰度化”說(shuō)起。
一:圖片灰度化
我們都知道,位圖是由一個(gè)一個(gè)像素點(diǎn)組成的,像素點(diǎn)可能是紅色,橙色,粉色等等,這些顏色我們都知道是用RGB來(lái)表示的。
每個(gè)顏色分量都是一個(gè)字節(jié)(0-255),所以一般情況下圖的像素點(diǎn)都是24位,當(dāng)然還有32位,64位,當(dāng)RGB是0-255之間的不同值時(shí),那么該像素點(diǎn)就呈現(xiàn)“五顏六色”,而當(dāng)RGB都是相同的值是,則像素點(diǎn)呈現(xiàn)“灰色”,如果大家玩過(guò)CSS的話,肯定都知道給一個(gè)字體的color通常都是#999999,#666666,#333333這些不同深度的灰色。
1.計(jì)算公式
下面我們?cè)撊绾卧O(shè)置合理的灰度值呢?當(dāng)然還是用當(dāng)前的RGB為模板,然后對(duì)RGB乘以一個(gè)合理的權(quán)重就ok了
Gary(i,j)=0.299*R(i,j)+0.587*G(i,j)+0.114*B(i,j);
2.編程
有了公式,實(shí)現(xiàn)起來(lái)就不成問(wèn)題了。Bitmap類(lèi)中有一個(gè)GetPixel/SetPixel,它可以獲取和設(shè)置當(dāng)前的像素點(diǎn)。
static void Main(string[] args) { Bitmap bitmap = new Bitmap(Environment.CurrentDirectory + "http://1.jpg"); for (int i = 0; i < bitmap.Width; i++) { for (int j = 0; j < bitmap.Height; j++) { //取圖片當(dāng)前的像素點(diǎn) var color = bitmap.GetPixel(i, j); var gray = (int)(color.R * 0.299 + color.G * 0.587 + color.B * 0.114); //重新設(shè)置當(dāng)前的像素點(diǎn) bitmap.SetPixel(i, j, Color.FromArgb(gray, gray, gray)); } } bitmap.Save(Environment.CurrentDirectory + "http://2.jpg"); }
3.改進(jìn)
上面這個(gè)方法很簡(jiǎn)單,Get/Set就Ok了,當(dāng)然這是我們站在像素點(diǎn)這個(gè)角度來(lái)考慮問(wèn)題的,貌似只要O(N2)的時(shí)間就可以KO問(wèn)題,但是Get/Set遠(yuǎn)遠(yuǎn)不是O(1)的,基于性能考慮,我們能不能有更優(yōu)的方法,此時(shí)我們可以站在字節(jié)這個(gè)角度思考,不過(guò)這里我們要注意一個(gè)問(wèn)題就是:比如圖片的width=21px,一個(gè)像素點(diǎn)占用3個(gè)字節(jié),但是21個(gè)像素點(diǎn)不一定就占用63個(gè)字節(jié),這是因?yàn)橄到y(tǒng)基于性能考慮,在每一行中存放著一個(gè)“未用區(qū)域”,來(lái)確保圖片每行的byte數(shù)是4的倍數(shù),那么如何去讀某一行的字節(jié)數(shù)呢?
C#里面有一個(gè)Stride屬性就可以用來(lái)獲取,很簡(jiǎn)單吧。
static void Main(string[] args) { Bitmap bitmap = new Bitmap(Environment.CurrentDirectory + "http://1.jpg"); //定義鎖定bitmap的rect的指定范圍區(qū)域 Rectangle rect = new Rectangle(0, 0, bitmap.Width, bitmap.Height); //加鎖區(qū)域像素 var bitmapData = bitmap.LockBits(rect, ImageLockMode.ReadWrite, bitmap.PixelFormat); //位圖的首地址 var ptr = bitmapData.Scan0; //stride:掃描行 int len = bitmapData.Stride * bitmap.Height; var bytes = new byte[len]; //鎖定區(qū)域的像素值copy到byte數(shù)組中 Marshal.Copy(ptr, bytes, 0, len); for (int i = 0; i < bitmap.Height; i++) { for (int j = 0; j < bitmap.Width * 3; j = j + 3) { var color = bytes[i * bitmapData.Stride + j + 2] * 0.299 + bytes[i * bitmapData.Stride + j + 1] * 0.597 + bytes[i * bitmapData.Stride + j] * 0.114; bytes[i * bitmapData.Stride + j] = bytes[i * bitmapData.Stride + j + 1] = bytes[i * bitmapData.Stride + j + 2] = (byte)color; } } //copy回位圖 Marshal.Copy(bytes, 0, ptr, len); //解鎖 bitmap.UnlockBits(bitmapData); bitmap.Save(Environment.CurrentDirectory + "http://3.jpg"); }
相關(guān)文章
C#通過(guò)NPOI導(dǎo)入導(dǎo)出數(shù)據(jù)EXCEL
這篇文章主要為大家詳細(xì)介紹了C#通過(guò)NPOI導(dǎo)入導(dǎo)出數(shù)據(jù)EXCEL,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-02-02c#開(kāi)發(fā)word批量轉(zhuǎn)pdf源碼分享
已經(jīng)安裝有Office環(huán)境,借助一些簡(jiǎn)單的代碼即可實(shí)現(xiàn)批量Word轉(zhuǎn)PDF,看下面的實(shí)例源碼吧2013-12-12C#客戶(hù)端HttpClient請(qǐng)求認(rèn)證及數(shù)據(jù)傳輸
本文詳細(xì)講解了C#客戶(hù)端HttpClient請(qǐng)求認(rèn)證及數(shù)據(jù)傳輸,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-01-01C# Socket連接請(qǐng)求超時(shí)機(jī)制實(shí)現(xiàn)代碼分享
這篇文章主要介紹了C# Socket連接請(qǐng)求超時(shí)機(jī)制實(shí)現(xiàn),下面提供代碼分享,大家可以參考使用2013-12-12c# 如何實(shí)現(xiàn)不同進(jìn)程之間的通信
這篇文章主要介紹了c# 如何實(shí)現(xiàn)不同進(jìn)程之間的通信,幫助大家更好的理解和學(xué)習(xí)c#,感興趣的朋友可以了解下2020-11-11c# DevExpress gridcontrol日期行的顯示格式設(shè)置
這篇文章主要介紹了c# DevExpress gridcontrol日期行的顯示格式設(shè)置,需要的朋友可以參考下2017-02-02