C#圖片灰度處理(位深度24→位深度8)


#region 灰度處理
        /// <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, YUI;



                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];
                        YUI = (byte)(0.229 * red + 0.587 * green + 0.144 * blue);
                        //grayValues[posDst] = (byte)((blue + green + red) / 3);
                        grayValues[posDst] = YUI;
                        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;
        }
        #endregion

 C#圖片二值化處理(位深度8→位深度1)

#region 二值化
/*
1位深度圖像 顏色表數組255個元素 只有用前兩個 0對應0  1對應255 
1位深度圖像每個像素占一位
8位深度圖像每個像素占一個字節  是1位的8倍
*/
        /// <summary>
        /// 將源灰度圖像二值化,並轉化為1位二值圖像。
        /// </summary>
        /// <param name="bmp"> 源灰度圖像。 </param>
        /// <returns> 1位二值圖像。 </returns>
        public static Bitmap GTo2Bit(Bitmap bmp)
        {
            if (bmp != null)
            {
                // 將源圖像內存區域鎖定
                Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
                BitmapData bmpData = bmp.LockBits(rect, ImageLockMode.ReadOnly,
                        PixelFormat.Format8bppIndexed);

                // 獲取圖像參數
                int leng, offset_1bit = 0;
                int width = bmpData.Width;
                int height = bmpData.Height;
                int stride = bmpData.Stride;  // 掃描線的寬度,比實際圖片要大
                int offset = stride - width;  // 顯示寬度與掃描線寬度的間隙
                IntPtr ptr = bmpData.Scan0;   // 獲取bmpData的內存起始位置的指針
                int scanBytesLength = stride * height;  // 用stride寬度,表示這是內存區域的大小
                if (width % 32 == 0)
                {
                    leng = width / 8;
                }
                else
                {
                    leng = width / 8 + (4 - (width / 8 % 4));
                    if (width % 8 != 0)
                    {
                        offset_1bit = leng - width / 8;
                    }
                    else
                    {
                        offset_1bit = leng - width / 8;
                    }
                }

                // 分別設置兩個位置指針,指向源數組和目標數組
                int posScan = 0, posDst = 0;
                byte[] rgbValues = new byte[scanBytesLength];  // 為目標數組分配內存
                Marshal.Copy(ptr, rgbValues, 0, scanBytesLength);  // 將圖像數據拷貝到rgbValues中
                // 分配二值數組
                byte[] grayValues = new byte[leng * height]; // 不含未用空間。
                // 計算二值數組
                int x, v, t = 0;
                for (int i = 0; i < height; i++)
                {
                    for (x = 0; x < width; x++)
                    {
                        v = rgbValues[posScan];
                        t = (t << 1) | (v > 100 ? 1 : 0);


                        if (x % 8 == 7)
                        {
                            grayValues[posDst] = (byte)t;
                            posDst++;
                            t = 0;
                        }
                        posScan++;
                    }

                    if ((x %= 8) != 7)
                    {
                        t <<= 8 - x;
                        grayValues[posDst] = (byte)t;
                    }
                    // 跳過圖像數據每行未用空間的字節,length = stride - width * bytePerPixel
                    posScan += offset;
                    posDst += offset_1bit;
                }

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

                // 構建1位二值位圖
                Bitmap retBitmap = twoBit(grayValues, width, height);
                return retBitmap;
            }
            else
            {
                return null;
            }
        }

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

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

            // 為圖像數據賦值
            int posScan = 0;                        // rawValues和grayValues的索引
            for (int i = 0; i < height; i++)
            {
                for (int j = 0; j < bmpData.Width / 8; j++)
                {
                    grayValues[posScan] = rawValues[posScan];
                    posScan++;
                }
                // 跳過圖像數據每行未用空間的字節,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.Format1bppIndexed))
            {
                palette = bmp.Palette;
            }
            for (int i = 0; i < 2; i = +254)
            {
                palette.Entries[i] = Color.FromArgb(i, i, i);
            }
            // 修改生成位圖的索引表
            bitmap.Palette = palette;

            return bitmap;
        }
        #endregion

 


免責聲明!

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



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