zoukankan      html  css  js  c++  java
  • x01.BitmapHelper:图像处理

    “所有致我于死地的,也激发我胆魄”,姚贝娜的《心火》,是我近年来听过最好的歌,特此推荐一下。

    图像处理,大概分三步:1.LockBits();2.进行处理;3.UnlockBits();这比起 C++ 来,不知清爽几许?

    编程,是为了满足人的需求,所以进行灰度处理时,不是简单的 (r + g + b) / 3,而是分别乘以合适的比例值,r * 0.30 + g * 0.59 + b * 0.11。这是因为人眼对 green 最敏感,red 次之,blue 最低。

    只实现了灰度处理,边缘提取,二值化,缩小,Rotate 等有限功能,代码不言自明,无需多说。

    using System;
    using System.Collections.Generic;
    using System.Drawing;
    using System.Drawing.Imaging;
    using System.Linq;
    using System.Runtime.InteropServices;
    using System.Text;
    
    namespace x01.Utilities
    {
        public static class BitmapHelper
        {
            /// <summary>
            /// 对 bitmap 进行灰度处理。r,g,b 权重相加为 1。
            /// </summary>
            /// <param name="bmp">所要处理的 bitmap 对象。</param>
            /// <param name="rWeight">red 权重。</param>
            /// <param name="gWeight">green 权重。</param>
            /// <param name="bWeight">blue 权重。</param>
            public static void Gray(Bitmap bmp, float rWeight = 0.30f, float gWeight = 0.59f, float bWeight = 0.11f)
            {
                BitmapData data = bmp.LockBits(new Rectangle(new Point(), bmp.Size), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
                byte[] buf = new byte[data.Stride * bmp.Height];
                Marshal.Copy(data.Scan0, buf, 0, buf.Length);
                for (int y = 0; y < bmp.Height * data.Stride; y += data.Stride)
                {
                    for (int x = 0; x < bmp.Width * 3; x += 3)
                    {
                        int i = y + x;
                        byte b = buf[i];
                        byte g = buf[i + 1];
                        byte r = buf[i + 2];
                        buf[i] = buf[i + 1] = buf[i + 2] = (byte)(b * bWeight + g * gWeight + r * rWeight);
                    }
                }
                Marshal.Copy(buf, 0, data.Scan0, buf.Length);
                bmp.UnlockBits(data);
            }
    
            /// <summary>
            /// 对 bitmap 进行中值滤波处理。
            /// </summary>
            /// <param name="bmp">所要处理的 bitmap 对象。</param>
            public static void MedianFilter(Bitmap bmp)
            {
                BitmapData data = bmp.LockBits(new Rectangle(new Point(), bmp.Size), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
                unsafe
                {
                    byte* pBuf = (byte*)data.Scan0.ToPointer();
                    for (int i = 1; i < bmp.Height - 1; i++)
                    {
                        for (int j = 1; j < bmp.Width - 1; j++)
                        {
                            List<byte>[] list = new List<byte>[3];
                            for (int k = 0; k < 3; k++)
                            {
                                list[k] = new List<byte>();
                            }
    
                            for (int y = -1; y < 2; y++)
                            {
                                for (int x = -1; x < 2; x++)
                                {
                                    int index = (i + y) * data.Stride + (j + x) * 3;
                                    for (int k = 0; k < 3; k++)
                                    {
                                        list[k].Add(pBuf[index + k]);
                                    }
                                }
                            }
    
                            for (int k = 0; k < 3; k++)
                            {
                                list[k].Sort();
                            }
    
                            int indexMedian = i * data.Stride + j * 3;
    
                            for (int k = 0; k < 3; k++)
                            {
                                pBuf[indexMedian + k] = list[k][4]; // 4: median value after sort.
                                list[k].Clear();
                            }
    
                            list = null;
                        }
                    }
                }
    
                bmp.UnlockBits(data);
            }
    
            /// <summary>
            /// 获取 bitmap 所选的颜色分量直方图。
            /// </summary>
            /// <param name="bmp">所要处理的 bitmap 对象</param>
            /// <param name="bgrOffset">所选的颜色: blue=0, green=1, red=2</param>
            /// <returns>返回 256 * 256 大小的 Bitmap 直方图。</returns>
            public static Bitmap Histogram(Bitmap bmp, int bgrOffset = 0)
            {
                BitmapData data = bmp.LockBits(new Rectangle(new Point(), bmp.Size), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
                byte[] buf = new byte[data.Stride * bmp.Height];
                Marshal.Copy(data.Scan0, buf, 0, buf.Length);
    
                int[] countColors = new int[256];
                for (int y = 0; y < bmp.Height; y++)
                {
                    for (int x = 0; x < bmp.Width; x++)
                    {
                        int index = y * data.Stride + x * 3;
                        countColors[buf[index + bgrOffset]]++;
                    }
                }
    
                bmp.UnlockBits(data);
    
                int maxIndex = 0;
                for (int i = 1; i < 256; i++)
                {
                    if (countColors[maxIndex] < countColors[i])
                    {
                        maxIndex = i;
                    }
                }
    
                Bitmap hist = new Bitmap(256, 256);
                Graphics g = Graphics.FromImage(hist);
                g.Clear(Color.Wheat);
                for (int i = 0; i < 256; i++)
                {
                    int h = 256 * countColors[i] / countColors[maxIndex];
                    g.DrawLine(new Pen(Color.FromArgb(i, i, i), 1f), i, 256, i, 256 - h); // top bottom inverse
                }
    
                return hist;
            }
    
            public static void ExtractEdge(Bitmap bmp)
            {
                BitmapData data = bmp.LockBits(new Rectangle(new Point(), bmp.Size), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
                byte[] buf = new byte[data.Stride * bmp.Height];
                byte[] edge = new byte[data.Stride * bmp.Height];
                Marshal.Copy(data.Scan0, buf, 0, buf.Length);
    
                for (int y = 1; y < bmp.Height - 1; y++)
                {
                    for (int x = 1; x < bmp.Width - 1; x++)
                    {
                        int index = y * data.Stride + x * 3;
                        byte gray = (byte)((buf[index] + buf[index + 1] + buf[index + 2]) / 3);
    
                        int value = 0;
                        for (int i = -1; i < 2; i++) // neareat eight point
                        {
                            for (int j = -1; j < 2; j++)
                            {
                                if (i == 0 && j == 0)
                                {
                                    continue;
                                }
    
                                int index2 = (y + i) * data.Stride + (x + i) * 3;
                                byte gray2 = (byte)((buf[index2] + buf[index2 + 1] + buf[index2 + 2]) / 3);
                                value += Math.Abs(gray - gray2);
                            }
                        }
    
                        edge[index] = edge[index + 1] = edge[index + 2] = (byte)(value >> 3);
                    }
                }
    
                Marshal.Copy(edge, 0, data.Scan0, edge.Length);
                bmp.UnlockBits(data);
            }
    
            /// <summary>
            /// 对图像进行二值化处理。
            /// </summary>
            /// <param name="bmp">处理的图像。</param>
            /// <param name="minValue">最小阀值。</param>
            /// <param name="maxValue">最大阀值。</param>
            public static void Binary(Bitmap bmp, int minValue, int maxValue)
            {
                BitmapData data = bmp.LockBits(new Rectangle(new Point(), bmp.Size), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
                byte[] buf = new byte[data.Stride * bmp.Height];
                Marshal.Copy(data.Scan0, buf, 0, buf.Length);
    
                for (int y = 0; y < bmp.Height; y++)
                {
                    for (int x = 0; x < bmp.Width; x++)
                    {
                        int index = y * data.Stride + x * 3;
                        int gray = (buf[index] + buf[index+1] +buf[index+2])/3;
                        if (gray >= minValue && gray <= maxValue)
                        {
                            buf[index] = buf[index + 1] = buf[index + 2] = 0;
                        }
                        else
                        {
                            buf[index] = buf[index + 1] = buf[index + 2] = 255;
                        }
                    }
                }
    
                Marshal.Copy(buf, 0, data.Scan0, buf.Length);
                bmp.UnlockBits(data);
            }
    
            /// <summary>
            /// 对灰度图像进行对比度增强。
            /// </summary>
            /// <param name="bmp">灰度图像</param>
            /// <param name="srcMin">原灰度下界</param>
            /// <param name="srcMax">原灰度上界</param>
            /// <param name="destMin">目标灰度下界</param>
            /// <param name="destMax">目标灰度上界</param>
            public static void Enhance(Bitmap bmp, int srcMin, int srcMax, int destMin, int destMax)
            {
                BitmapData data = bmp.LockBits(new Rectangle(new Point(), bmp.Size), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
                byte[] buf = new byte[data.Stride * bmp.Height];
                Marshal.Copy(data.Scan0, buf, 0, buf.Length);
    
                for (int y = 0; y < bmp.Height; y++)
                {
                    for (int x = 0; x < bmp.Width; x++)
                    {
                        int index = y * data.Stride + x * 3;
                        int gray = (buf[index] + buf[index + 1] + buf[index + 2]) / 3;
                        float value = (float)(destMax - destMin) / (srcMax - srcMin) * (gray - srcMin) + destMin;
                        buf[index] = buf[index + 1] = buf[index + 2] = 
                            value < byte.MinValue ? byte.MinValue : (value > byte.MaxValue ? byte.MaxValue : (byte)value);
                    }
                }
    
                Marshal.Copy(buf, 0, data.Scan0, buf.Length);
    
                bmp.UnlockBits(data);
            }
    
            public static void Enhance(Bitmap bmp, float n)
            {
                BitmapData data = bmp.LockBits(new Rectangle(new Point(), bmp.Size), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
                byte[] buf = new byte[data.Stride * bmp.Height];
                Marshal.Copy(data.Scan0, buf, 0, buf.Length);
    
                for (int y = 0; y < bmp.Height; y++)
                {
                    for (int x = 0; x < bmp.Width; x++)
                    {
                        int index = y * data.Stride + x * 3;
                        int gray = (buf[index] + buf[index + 1] + buf[index + 2]) / 3;
                        float value = gray * n;
                        buf[index] = buf[index + 1] = buf[index + 2] =
                            value < byte.MinValue ? byte.MinValue : (value > byte.MaxValue ? byte.MaxValue : (byte)value);
                    }
                }
    
                Marshal.Copy(buf, 0, data.Scan0, buf.Length);
                bmp.UnlockBits(data);
            }
    
            public static void ConnectRegion(Bitmap bmp)
            {
                BitmapData data = bmp.LockBits(new Rectangle(new Point(), bmp.Size), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
                byte[] buf = new byte[data.Stride * bmp.Height];
                Marshal.Copy(data.Scan0, buf, 0, buf.Length);
    
                int sign = 40;
                for (int y = 0; y < bmp.Height; y++)
                {
                    for (int x = 0; x < bmp.Width; x++)
                    {
                        int index = y * data.Stride + x * 3;
                        if (buf[index] == 0)
                        {
                            SignRegion(buf, x * 3, y * data.Stride, sign, data.Stride, bmp.Width, bmp.Height);
                            sign += 40;
                        }
                    }
                }
                
                Marshal.Copy(buf, 0, data.Scan0, buf.Length);
                bmp.UnlockBits(data);
            }
    
            public static void SignRegion(byte[] buf, int x, int y, int sign, int stride, int width, int height)
            {
                int index = x + y;
                buf[index] = buf[index + 1] = buf[index + 2] = (byte)sign;
                
                if (x > 0 && buf[index -3] == 0)    // left
                {
                    SignRegion(buf, x - 3, y, sign, stride, width, height);
                }
    
                if (x < width * 3 - 3 && buf[index + 3] == 0) // right
                {
                    SignRegion(buf, x + 3, y, sign, stride, width, height);
                }
    
                if (y > 0 && buf[index - stride] == 0)  // top
                {
                    SignRegion(buf, x, y - stride, sign, stride, width, height);
                }
    
                if (y < height * stride && buf[index + stride] == 0) // bottom
                {
                    SignRegion(buf, x, y + stride, sign, stride, width, height);
                }
    
            }
    
            /// <summary>
            /// 缩小图像。
            /// </summary>
            /// <param name="bmp">图像</param>
            /// <param name="widthFactor">宽度缩小倍数</param>
            /// <param name="heightFactor">高度缩小倍数</param>
            public static void Dilation(Bitmap bmp, float widthFactor, float heightFactor)
            {
                BitmapData data = bmp.LockBits(new Rectangle(new Point(), bmp.Size), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
                byte[] buf = new byte[data.Stride * bmp.Height];
                Marshal.Copy(data.Scan0, buf, 0, buf.Length);
    
                byte[] result = new byte[data.Stride * bmp.Height];
                for (int y = 0; y < bmp.Height; y++)
                {
                    for (int x = 0; x < bmp.Width; x++)
                    {
                        int index = y * data.Stride + x * 3;
                        
                        int rx = (int)(x * widthFactor);
                        int ry = (int)(y * heightFactor);
                        if (rx < 0 || rx >= bmp.Width || ry < 0 || ry >= bmp.Height)
                        {
                            continue;
                        }
                        int rindex = ry * data.Stride + rx * 3;
    
                        result[index] = buf[rindex];
                        result[index + 1] = buf[rindex + 1];
                        result[index + 2] = buf[rindex + 2];
                    }
                }
    
                Marshal.Copy(result, 0, data.Scan0, result.Length);
                bmp.UnlockBits(data);
            }
    
            public static void Translate(Bitmap bmp, int xOffset, int yOffset)
            {
                BitmapData data = bmp.LockBits(new Rectangle(new Point(), bmp.Size), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
                byte[] buf = new byte[data.Stride * bmp.Height];
                Marshal.Copy(data.Scan0, buf, 0, buf.Length);
    
                byte[] result = new byte[data.Stride * bmp.Height];
                for (int y = 0; y < bmp.Height; y++)
                {
                    for (int x = 0; x < bmp.Width; x++)
                    {
                        int index = y * data.Stride + x * 3;
    
                        int rx = x - xOffset;
                        int ry = y - yOffset;
                        if (rx < 0 || rx >= bmp.Width || ry < 0 || ry >= bmp.Height)
                        {
                            continue;
                        }
                        int rindex = ry * data.Stride + rx * 3;
    
                        result[index] = buf[rindex];
                        result[index + 1] = buf[rindex + 1];
                        result[index + 2] = buf[rindex + 2];
                    }
                }
    
                Marshal.Copy(result, 0, data.Scan0, result.Length);
                bmp.UnlockBits(data);
            }
    
            public static void Rotate(Bitmap bmp, float angle, Point center)
            {
                BitmapData data = bmp.LockBits(new Rectangle(new Point(), bmp.Size), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
                byte[] buf = new byte[data.Stride * bmp.Height];
                Marshal.Copy(data.Scan0, buf, 0, buf.Length);
    
                byte[] result = new byte[data.Stride * bmp.Height];
                for (int y = 0; y < bmp.Height; y++)
                {
                    for (int x = 0; x < bmp.Width; x++)
                    {
                        int index = y * data.Stride + x * 3;
    
                        int rx = (int)( (x - center.X) * Math.Cos(angle * Math.PI / 180) 
                            - (y - center.Y) * Math.Sin(angle * Math.PI / 180)  +  center.X );
                        int ry = (int)( (x - center.X) * Math.Sin(angle * Math.PI / 180)
                            + (y - center.Y) * Math.Cos(angle * Math.PI / 180) + center.Y );
    
                        if (rx < 0 || rx >= bmp.Width || ry < 0 || ry >= bmp.Height)
                        {
                            continue;
                        }
                        int rindex = ry * data.Stride + rx * 3;
    
                        result[index] = buf[rindex];
                        result[index + 1] = buf[rindex + 1];
                        result[index + 2] = buf[rindex + 2];
                    }
                }
    
                Marshal.Copy(result, 0, data.Scan0, result.Length);
                bmp.UnlockBits(data);
            }
        }
    }
    BitmapHelper

    如果要处理图像,Paint.Net 是款不错的软件。

  • 相关阅读:
    Codeforces Round #674 (Div. 3)C. Increase and Copy
    Calendar Game
    poj3255Roadblocks
    L2-008 最长对称子串
    L2-004 这是二叉搜索树吗?
    D. Boboniu Chats with Du Codeforces Round #664 (Div. 2)
    暑假了,冲冲冲
    逆元和同余
    懒惰的我
    Codeforces Round #594 (Div. 2) C题
  • 原文地址:https://www.cnblogs.com/china_x01/p/3376636.html
Copyright © 2011-2022 走看看