玩玩圖形圖像——第一篇:圖片灰度化


 

    去年買了本數字圖像處理算法,一直都沒有看,前幾個星期都一直忙着工作上的活,趁這階段悠閑點,玩一玩圖片處理,這玩意

還是非常有意思的。

   以前我們在做Web上的用戶注冊時,通常都會做一個驗證碼,大家都知道用來防止暴力注冊的,當然提到驗證碼大家都知道C#里

面有一個Bitmap類專門用來處理圖片的,好吧,這一篇我們從最簡單的“圖片灰度化”說起。

一:圖片灰度化

     我們都知道,位圖是由一個一個像素點組成的,像素點可能是紅色,橙色,粉色等等,這些顏色我們都知道是用RGB來表示的。

每個顏色分量都是一個字節(0-255),所以一般情況下圖的像素點都是24位,當然還有32位,64位,當RGB是0-255之間的不同值

時,那么該像素點就呈現“五顏六色”,而當RGB都是相同的值是,則像素點呈現“灰色”,如果大家玩過CSS的話,肯定都知道給一個

字體的color通常都是#999999,#666666,#333333這些不同深度的灰色。

1.計算公式

   下面我們該如何設置合理的灰度值呢?當然還是用當前的RGB為模板,然后對RGB乘以一個合理的權重就ok了

   Gary(i,j)=0.299*R(i,j)+0.587*G(i,j)+0.114*B(i,j);

2.編程

  有了公式,實現起來就不成問題了。Bitmap類中有一個GetPixel/SetPixel,它可以獲取和設置當前的像素點。

        static void Main(string[] args)
        {
            Bitmap bitmap = new Bitmap(Environment.CurrentDirectory + "//1.jpg");

            for (int i = 0; i < bitmap.Width; i++)
            {
                for (int j = 0; j < bitmap.Height; j++)
                {
                    //取圖片當前的像素點
                    var color = bitmap.GetPixel(i, j);

                    var gray = (int)(color.R * 0.299 + color.G * 0.587 + color.B * 0.114);

                    //重新設置當前的像素點
                    bitmap.SetPixel(i, j, Color.FromArgb(gray, gray, gray));
                }
            }

            bitmap.Save(Environment.CurrentDirectory + "//2.jpg");
        }

  

3.改進

   上面這個方法很簡單,Get/Set就Ok了,當然這是我們站在像素點這個角度來考慮問題的,貌似只要O(N2)的時間就可以KO問

題,但是Get/Set遠遠不是O(1)的,基於性能考慮,我們能不能有更優的方法,此時我們可以站在字節這個角度思考,不過這里我

們要注意一個問題就是:比如圖片的width=21px,一個像素點占用3個字節,但是21個像素點不一定就占用63個字節,這是因為

系統基於性能考慮,在每一行中存放着一個“未用區域”,來確保圖片每行的byte數是4的倍數,那么如何去讀某一行的字節數呢?

C#里面有一個Stride屬性就可以用來獲取,很簡單吧。

static void Main(string[] args)
        {
            Bitmap bitmap = new Bitmap(Environment.CurrentDirectory + "//1.jpg");

            //定義鎖定bitmap的rect的指定范圍區域
            Rectangle rect = new Rectangle(0, 0, bitmap.Width, bitmap.Height);

            //加鎖區域像素
            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];

            //鎖定區域的像素值copy到byte數組中
            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 + "//3.jpg");
        }

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM