C# 圖像處理:將圖像(24位真彩)轉為 8位灰度圖像 采用了內存法,大大提高了效率


        /// <summary>
        /// 將源圖像灰度化,並轉化為8位灰度圖像。
        /// </summary>
        /// <param name="original"> 源圖像。 </param>
        /// <returns> 8位灰度圖像。 </returns>
        public static Bitmap RgbToGrayScale(Bitmap original)
        {
            if (original != null)
            {
                // 將源圖像內存區域鎖定
                Rectangle rect = new Rectangle(0, 0, original.Width, original.Height);
                BitmapData bmpData = original.LockBits(rect, ImageLockMode.ReadOnly,
                        PixelFormat.Format24bppRgb);

                // 獲取圖像參數
                int width = bmpData.Width;
                int height = bmpData.Height;
                int stride = bmpData.Stride;  // 掃描線的寬度,比實際圖片要大
                int offset = stride - width * 3;  // 顯示寬度與掃描線寬度的間隙
                IntPtr ptr = bmpData.Scan0;   // 獲取bmpData的內存起始位置的指針
                int scanBytesLength = stride * height;  // 用stride寬度,表示這是內存區域的大小

                // 分別設置兩個位置指針,指向源數組和目標數組
                int posScan = 0, posDst = 0;
                byte[] rgbValues = new byte[scanBytesLength];  // 為目標數組分配內存
                Marshal.Copy(ptr, rgbValues, 0, scanBytesLength);  // 將圖像數據拷貝到rgbValues中
                // 分配灰度數組
                byte[] grayValues = new byte[width * height]; // 不含未用空間。
                // 計算灰度數組

                byte blue, green, red;



                for (int i = 0; i < height; i++)
                {
                    for (int j = 0; j < width; j++)
                    {

                        blue = rgbValues[posScan];
                        green = rgbValues[posScan + 1];
                        red = rgbValues[posScan + 2];
                        grayValues[posDst] = (byte)((blue + green+red)/3);
                        posScan += 3;
                        posDst++;

                    }
                    // 跳過圖像數據每行未用空間的字節,length = stride - width * bytePerPixel
                    posScan += offset;
                }

                // 內存解鎖
                Marshal.Copy(rgbValues, 0, ptr, scanBytesLength);
                original.UnlockBits(bmpData);  // 解鎖內存區域

                // 構建8位灰度位圖
                Bitmap retBitmap = BuiltGrayBitmap(grayValues, width, height);
                return retBitmap;
            }
            else
            {
                return null;
            }
        }

        /// <summary>
        /// 用灰度數組新建一個8位灰度圖像。
        /// </summary>
        /// <param name="rawValues"> 灰度數組(length = width * height)。 </param>
        /// <param name="width"> 圖像寬度。 </param>
        /// <param name="height"> 圖像高度。 </param>
        /// <returns> 新建的8位灰度位圖。 </returns>
        private static Bitmap BuiltGrayBitmap(byte[] rawValues, int width, int height)
        {
            // 新建一個8位灰度位圖,並鎖定內存區域操作
            Bitmap bitmap = new Bitmap(width, height, PixelFormat.Format8bppIndexed);
            BitmapData bmpData = bitmap.LockBits(new Rectangle(0, 0, width, height),
                 ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed);

            // 計算圖像參數
            int offset = bmpData.Stride - bmpData.Width;        // 計算每行未用空間字節數
            IntPtr ptr = bmpData.Scan0;                         // 獲取首地址
            int scanBytes = bmpData.Stride * bmpData.Height;    // 圖像字節數 = 掃描字節數 * 高度
            byte[] grayValues = new byte[scanBytes];            // 為圖像數據分配內存

            // 為圖像數據賦值
            int posSrc = 0, posScan = 0;                        // rawValues和grayValues的索引
            for (int i = 0; i < height; i++)
            {
                for (int j = 0; j < width; j++)
                {
                    grayValues[posScan++] = rawValues[posSrc++];
                }
                // 跳過圖像數據每行未用空間的字節,length = stride - width * bytePerPixel
                posScan += offset;
            }

            // 內存解鎖
            Marshal.Copy(grayValues, 0, ptr, scanBytes);
            bitmap.UnlockBits(bmpData);  // 解鎖內存區域

            // 修改生成位圖的索引表,從偽彩修改為灰度
            ColorPalette palette;
            // 獲取一個Format8bppIndexed格式圖像的Palette對象
            using (Bitmap bmp = new Bitmap(1, 1, PixelFormat.Format8bppIndexed))
            {
                palette = bmp.Palette;
            }
            for (int i = 0; i < 256; i++)
            {
                palette.Entries[i] = Color.FromArgb(i, i, i);
            }
            // 修改生成位圖的索引表
            bitmap.Palette = palette;

            return bitmap;
        }

 


免責聲明!

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



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