精华内容
下载资源
问答
  • 描述了图像灰度化MATLAB程序,还有二值化的程序
  • C语言实现的图像灰度化二值化源代码,不依赖任何第三方库,不使用OPENCV,纯C实现!方便初学者一学即会!
  • .NET Core 图像处理(图像二值化,图像灰度化,图像灰度反转) ImageSharp 是支持.NET Core跨平台图形处理库,本文将利用ImageSharp库实现图像二值化,图像灰度化,图像灰度反转。 图像二值化 public static ...

    ImageSharp 是支持.NET Core跨平台图形处理库,本文将利用ImageSharp库实现图像二值化,图像灰度化,图像灰度反转。

    • 图像二值化
    public static Image<Rgba32> Binaryzation(Image<Rgba32> image)
    {
         int avg = 0;
         for (int i = 0; i < image.Width; i++)
         {
             for (int j = 0; j < image.Height; j++)
             {
                 var color = image.GetPixelReference(i, j);
                 avg += color.B;
             }
         }
         avg = (int)avg / (image.Width * image.Height);
    
         for (int i = 0; i < image.Width; i++)
         {
             for (int j = 0; j < image.Height; j++)
             {
                 //获取该像素点的RGB的颜色
                 var color = image.GetPixelReference(i, j);
                 int value = 255 - color.B;
                 //计算颜色,大于平均值为黑,小于平均值为黑
                 Color newColor = value > avg ? Color.FromArgb(0, 0, 0) : Color.FromArgb(255,255,255);
                 //修改该像素点的RGB的颜色
                 image.GetPixelReference(i, j).Rgba =(uint)newColor.ToArgb();
             }
         }
         return image;
    }
    
    • 图像灰度化
    public static Image<Rgba32> GrayProcessing(Image<Rgba32> image)
    {
        for (int i = 0; i < image.Width; i++)
        {
            for (int j = 0; j < image.Height; j++)
            {
                //获取该像素点的RGB的颜色
                var color = image.GetPixelReference(i, j);
                //计算灰度值
                int gray = (int)(color.R * 0.3 + color.G * 0.59 + color.B * 0.11);
                Color newColor = Color.FromArgb(gray, gray, gray);
                //修改该像素点的RGB的颜色
                image.GetPixelReference(i, j).Rgba = (uint)newColor.ToArgb();
            }
        }
        return image;
    }
    
    • 图像灰度反转
     public static Image<Rgba32> GrayReversal(Image<Rgba32> image)
     {
         for (int i = 0; i < image.Width; i++)
         {
             for (int j = 0; j < image.Height; j++)
             {
                 //获取该像素点的RGB的颜色
                 var color = image.GetPixelReference(i, j);
                 //取相反色
                 Color newColor = Color.FromArgb(255-color.R,255-color.G,255-color.B);
                 //修改该像素点的RGB的颜色
                 image.GetPixelReference(i, j).Rgba = (uint)newColor.ToArgb();
             }
         }
         return image;
     }
    
    展开全文
  • 图像灰度化二值化

    2021-03-03 21:45:03
    图像灰度化: 灰度图像上每个像素的颜色又称为灰度,指黑白图像中点的颜色深度,范围一般从0到255,白色为255,黑色为0。所谓灰度是指色彩的浓淡程度,灰度直方图是指一幅数字图像中,对应每一个灰度统计出...

    图像灰度化:
    灰度图像上每个像素的颜色值又称为灰度,指黑白图像中点的颜色深度,范围一般从0到255,白色为255,黑色为0。所谓灰度值是指色彩的浓淡程度,灰度直方图是指一幅数字图像中,对应每一个灰度值统计出具有该灰度值的象素数。

    灰度就是没有色彩,RGB色彩分量全部相等。如果是一个二值灰度图象,它的象素值只能为0或1,我们说它的灰度级为2。用个例子来说明吧:一个256级灰度的图象,如果RGB三个量相同时,如:RGB(100,100,100)就代表灰度为100,RGB(50,50,50)代表灰度为50。

    现在大部分的彩色图像都是采用RGB颜色模式,处理图像的时候,要分别对RGB三种分量进行处理,实际上RGB并不能反映图像的形态特征,只是从光学的原理上进行颜色的调配。

    图像灰度化处理可以作为图像处理的预处理步骤,为之后的图像分割、图像识别和图像分析等上层操作做准备。

    图像二值化:

    图像的二值化处理就是讲图像上的点的灰度置为0或255,也就是讲整个图像呈现出明显的黑白效果。即将256个亮度等级的灰度图像通过适当的阀值选取而获得仍然可以反映图像整体和局部特征的二值化图像。在数字图像处理中,二值图像占有非常重要的地位,特别是在实用的图像处理中,以二值图像处理实现而构成的系统是很多的,要进行二值图像的处理与分析,首先要把灰度图像二值化,得到二值化图像,这样子有利于再对图像做进一步处理时,图像的集合性质只与像素值为0或255的点的位置有关,不再涉及像素的多级值,使处理变得简单,而且数据的处理和压缩量小。为了得到理想的二值图像,一般采用封闭、连通的边界定义不交叠的区域。所有灰度大于或等于阀值的像素被判定为属于特定物体,其灰度值为255表示,否则这些像素点被排除在物体区域以外,灰度值为0,表示背景或者例外的物体区域。如果某特定物体在内部有均匀一致的灰度值,并且其处在一个具有其他等级灰度值的均匀背景下,使用阀值法就可以得到比较的分割效果。如果物体同背景的差别表现不在灰度值上(比如纹理不同),可以将这个差别特征转换为灰度的差别,然后利用阀值选取技术来分割该图像。动态调节阀值实现图像的二值化可动态观察其分割图像的具体结果。

    代码:

    one = 0;
    two = 0;
    data = imread('1.jpg');
    subplot(221);
    imshow(data);
    gdata = rgb2gray(data);
    subplot(222);
    imshow(gdata);
    n = graythresh(gdata);
    bw=im2bw(data,n);
    subplot(223);
    imshow(bw);
    for i = 1:1080
        for j = 1:1920
            if bw(i,j) == 0
                one = one + 1;
            else two = two + 1;
            end
        end
    end
    disp(one/(one+two));
    
    展开全文
  • 为加快处理速度,在图像处理算法中,往往需要把彩色图像转换为灰度图像,在灰度图像上...当R、G、B分量相同时,表现为灰度图像,该就是我们所求的一般来说,转换公式有3种。第一种转换公式为: Gray(i,j)=[R(i,j)+G(i...

    为加快处理速度,在图像处理算法中,往往需要把彩色图像转换为灰度图像,在灰度图像上得到验证的算法,很容易移
    植到彩色图像上。
    24位彩色图像每个像素用3个字节表示,每个字节对应着R、G、B分量的亮度(红、绿、蓝)。当R、G、B分量值不同时,表现为彩色图像;当R、G、B分量值相同时,表现为灰度图像,该值就是我们所求的一般来说,转换公式有3种。第一种转换公式为:

    Gray(i,j)=[R(i,j)+G(i,j)+B(i,j)]÷3            (2.1)

    其中,Gray(i,j)为转换后的灰度图像在(i,j)点处的灰度值。该方法虽然简单,但人眼对颜色的感应是不同的,因此有了第二种转换公式:

    Gray(i,j)=0299R(i,j)+0.587×G(i,j)+0.114×B(i,j)      (2.2)

    观察上式,发现绿色所占的比重最大,所以转换时可以直接使用G值作为转换后的灰度

    Gray(i,j)=G(i,j)                    (2.3)

    在这里,我们应用最常用的公式(2.2),并且变换后的灰度图像仍然用24位图像表示。

     

    1.提取像素法

    这种方法简单易懂,但相当耗时,完全不可取.
    该方法使用的是GD+中的 Bitmap Getpixel和 BitmapSetpixel.方法。为了将位图的颜色设置为灰度或其他颜色,就需要使用 Gepiⅸxel来读取当前像素的颜色,再计算灰度值,最后使用 Setpixel来应用新的颜色。双击“提取像素法” Button控件,为该控件添加 Click事件,

    代码如下:

         /// <summary>
            /// 提取像素法
            /// </summary>
            private void pixel_Click(object sender, EventArgs e)
            {if (curBitmpap != null)
                {
                    Color curColor;
                    int ret;
    
                    //二维图像数组循环
                    for(int i = 0; i < curBitmpap.Width; i++)
                    {
                        for(int j = 0; j < curBitmpap.Height; j++)
                        {
                            //获取该像素点的RGB颜色值
                            curColor = curBitmpap.GetPixel(i, j);
                            //利用公式计算灰度值
                            ret = (int)(curColor.R * 0.299 + curColor.G * 0.587 + curColor.B * 0.114);
                            //设置该像素点的灰度值,R=G=B=ret
                            curBitmpap.SetPixel(i, j, Color.FromArgb(ret, ret, ret));
                        }
                    }//对窗体进行重新绘制,这将强制执行Paint事件处理程序
                    Invalidate();
                }
            }

     


    2.内存法
    该方法就是把图像数据直接复制到内存中,这样就使程序的运行速度大大提高。双击“内存法”按钮控件,为该控件添加Cick事件,代码如下:

         /// <summary>
            /// 内存法(适用于任意大小的24位彩色图像)
            /// </summary>
            private void memory_Click(object sender, EventArgs e)
            {if (curBitmpap != null)
                {
                    //位图矩形
                    Rectangle rect = new Rectangle(0, 0, curBitmpap.Width, curBitmpap.Height);
                    //以可读写的方式锁定全部位图像素
                    System.Drawing.Imaging.BitmapData bmpData = curBitmpap.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, curBitmpap.PixelFormat);
                    //得到首地址
                    IntPtr ptr = bmpData.Scan0;
    
                    //定义被锁定的数组大小,由位图数据与未用空间组成的
                    int bytes = bmpData.Stride * bmpData.Height;
                    //定义位图数组
                    byte[] rgbValues = new byte[bytes];
                    //复制被锁定的位图像素值到该数组内
                    System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, bytes);
    
                    //灰度化
                    double colorTemp = 0;
                    for (int i = 0; i < bmpData.Height; i++)
                    {
                        //只处理每行中是图像像素的数据,舍弃未用空间
                        for (int j = 0; j < bmpData.Width * 3; j += 3)
                        {
                            //利用公式计算灰度值
                            colorTemp = rgbValues[i * bmpData.Stride + j + 2] * 0.299 + rgbValues[i * bmpData.Stride + j + 1] * 0.587 + rgbValues[i * bmpData.Stride + j] * 0.114;
                            //R=G=B
                            rgbValues[i * bmpData.Stride + j] = rgbValues[i * bmpData.Stride + j + 1] = rgbValues[i * bmpData.Stride + j + 2] = (byte)colorTemp;
                        }
                    }
    
                    //把数组复制回位图
                    System.Runtime.InteropServices.Marshal.Copy(rgbValues, 0, ptr, bytes);
                    //解锁位图像素
                    curBitmpap.UnlockBits(bmpData);//对窗体进行重新绘制,这将强制执行Paint事件处理程序
                    Invalidate();
                }
            }

     

    3.指针法
    该方法与内存法相似,开始都是通过 Lockbits方法来获取位图的首地址。但该方法更简洁,直接应用指针对位图进行操作。

    为了保持类型安全,在默认情况下,C#是不支持指针运算的,因为使用指针会带来相关的风险。所以C#只允许在特别标记的代码块中使用指针。通过使用 unsafe关键字,可以定义可使用指针的不安全上下文。

    双击“指针法”按钮控件,为该控件添加 Click事件,代码如下:

         /// <summary>
            /// 指针法
            /// </summary>
            private void pointer_Click(object sender, EventArgs e)
            {if (curBitmpap != null)
                {
                    //位图矩形
                    Rectangle rect = new Rectangle(0, 0, curBitmpap.Width, curBitmpap.Height);
                    //以可读写的方式锁定全部位图像素
                    System.Drawing.Imaging.BitmapData bmpData = curBitmpap.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, curBitmpap.PixelFormat);
    
                    byte temp = 0;
                    //启用不安全模式
                    unsafe
                    {
                        //得到首地址
                        byte* ptr = (byte*)(bmpData.Scan0);
                        //二维图像循环
                        for (int i = 0; i < bmpData.Height; i++)
                        {
                            for (int j = 0; j < bmpData.Width; j++)
                            {
                                //利用公式计算灰度值
                                temp = (byte)(0.299 * ptr[2] + 0.587 * ptr[1] + 0.114 * ptr[0]);
                                //R=G=B
                                ptr[0] = ptr[1] = ptr[2] = temp;
                                //指向下一个像素
                                ptr += 3;
                            }
                            //指向下一行数组的首个字节
                            ptr += bmpData.Stride - bmpData.Width * 3;
                        }
                    }
                    //解锁位图像素
                    curBitmpap.UnlockBits(bmpData);//对窗体进行重新绘制,这将强制执行Paint事件处理程序
                    Invalidate();
                }
            }

    由于启动了不安全模式,为了能够顺利地编译该段代码,必须设置相关选项。在主菜单中选择“项目|gray属性”,在打开的属性页中选择“生成”属性页,最后选中“允许不安全代码”复选框。

     

    三种方法的比较

    从3段代码的长度和难易程度来看,提取像素法又短又简单。它直接应用GD+中的Bitmap. Getpixel方法和 Bitmap. Setpixel方法,大大减少了代码的长度,降低了使用者的难度,并且可读性好。但衡量程序好坏的标准不是仅仅看它的长度和难易度,而是要看它的效率,尤其是像图像处理这种往往需要处理二维数据的大信息量的应用领域,就更需要考虑效率了为了比较这3种方法的效率,我们对其进行计时。首先在主窗体内添加一个 Label控件和 Textbox控件。

     

    添加一个类:HiPerfTimer

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Runtime.InteropServices;
    using System.ComponentModel;
    using System.Threading;
    
    namespace gray
    {
        internal class HiPerfTimer
        {
            //引用win32API中的QueryPerformanceCounter()方法
            //该方法用来查询任意时刻高精度计数器的实际值
            [DllImport("Kernel32.dll")]         //using System.Runtime.InteropServices;
            private static extern bool QueryPerformanceCounter(out long lpPerformanceCount);
    
            //引用win32API中的QueryPerformanceCounter()方法
            //该方法用来查询任意时刻高精度计数器的实际值
            [DllImport("Kernel32.dll")]
            private static extern bool QueryPerformanceFrequency(out long lpFrequency);
    
            private long startTime, stopTime;
            private long freq;
    
            public HiPerfTimer()
            {
                startTime = 0;
                stopTime = 0;
    
                if(QueryPerformanceFrequency(out freq) == false)
                {
                    //不支持高性能计时器
                    throw new Win32Exception();     //using System.ComponentModel;
                }
            }
    
            //开始计时
            public void Start()
            {
                //让等待线程工作
                Thread.Sleep(0);                //using System.Threading;
    
                QueryPerformanceCounter(out startTime);
            }
            //结束计时
            public void Stop()
            {
                QueryPerformanceCounter(out stopTime);
            }
            //返回计时结果(ms)
            public double Duration
            {
                get
                {
                    return (double)(stopTime - startTime) * 1000 / (double)freq;
                }
            }
    
        }
    }

    在Form1类内定义HiPerfTimer类并在构造函数内为其实例化

            private HiPerfTimer myTimer;
            public Form1()
            {
                InitializeComponent();
                myTimer = new gray.HiPerfTimer();
            }

     

    分别在“提取像素法”、“内存法”和“指针法” Button控件的 Click事件程序代码内的

    if判断语句之间的最开始一行添加以下代码:

                //启动计时器
                myTimer.Start();

    在上述3个单击事件内的 Invalidate0语句之前添加以下代码:

                 //关闭计时器
                 myTimer.Stop();
                 //在TextBox内显示计时时间
                 timeBox.Text = myTimer.Duration.ToString("####.##") + "毫秒";

     

    最后,编译并运行该段程序。可以明显看出,内存法和指针法比提取像素法要快得多。提取像素法应用GDI+中的方法,易于理解,方法简单,很适合于C#的初学者使用,但它的运行速度最慢,效率最低。内存法把图像复制到内存中,直接对内存中的数据进行处理,速度明显提高,程序难度也不大。指针法直接应用指针来对图像进行处理,所以速度最快。但在C#中是不建议使用指针的,因为使用指针,代码不仅难以编写和调试,而且无法通过CLR的内存类型安全检查,不能发挥C#的特长。只有对C#和指针有了充分的理解,才能用好该方法。究竟要使用哪种方法,还要看具体情况而定。但3种方法都能有效地对图像进行处理。

     

    全文代码:

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows.Forms;
    
    namespace gray
    {
        public partial class Form1 : Form
        {
            private HiPerfTimer myTimer;
            public Form1()
            {
                InitializeComponent();
                myTimer = new gray.HiPerfTimer();
            }
    
            //文件名
            private string curFileName;
            //图像对象
            private System.Drawing.Bitmap curBitmpap;
    
            /// <summary>
            /// 打开图像文件
            /// </summary>
            private void open_Click(object sender, EventArgs e)
            {
                //创建OpenFileDialog
                OpenFileDialog opnDlg = new OpenFileDialog();
                //为图像选择一个筛选器
                opnDlg.Filter = "所有图像文件|*.bmp;*.pcx;*.png;*.jpg;*.gif;" +
                    "*.tif;*.ico;*.dxf;*.cgm;*.cdr;*.wmf;*.eps;*.emf|" +
                    "位图(*.bmp;*.jpg;*.png;...)|*.bmp;*.pcx;*.png;*.jpg;*.gif;*.tif;*.ico|" +
                    "矢量图(*.wmf;*.eps;*.emf;...)|*.dxf;*.cgm;*.cdr;*.wmf;*.eps;*.emf";
                //设置对话框标题
                opnDlg.Title = "打开图像文件";
                //启用“帮助”按钮
                opnDlg.ShowHelp = true;
    
                //如果结果为“打开”,选定文件
                if(opnDlg.ShowDialog()==DialogResult.OK)
                {
                    //读取当前选中的文件名
                    curFileName = opnDlg.FileName;
                    //使用Image.FromFile创建图像对象
                    try
                    {
                        curBitmpap = (Bitmap)Image.FromFile(curFileName);
                    }
                    catch(Exception exp)
                    {
                        MessageBox.Show(exp.Message);
                    }
                }
                //对窗体进行重新绘制,这将强制执行paint事件处理程序
                Invalidate();
            }
    
            private void Form1_Paint(object sender, PaintEventArgs e)
            {
                //获取Graphics对象
                Graphics g = e.Graphics;
                if (curBitmpap != null)
                {
                    //使用DrawImage方法绘制图像
                    //160,20:显示在主窗体内,图像左上角的坐标
                    //curBitmpap.Width, curBitmpap.Height图像的宽度和高度
                    g.DrawImage(curBitmpap, 160, 20, curBitmpap.Width, curBitmpap.Height);
                }
            }
    
            /// <summary>
            /// 保存图像文件
            /// </summary>
            private void save_Click(object sender, EventArgs e)
            {
                //如果没有创建图像,则退出
                if (curBitmpap == null)
                    return;
    
                //调用SaveFileDialog
                SaveFileDialog saveDlg = new SaveFileDialog();
                //设置对话框标题
                saveDlg.Title = "保存为";
                //改写已存在文件时提示用户
                    saveDlg.OverwritePrompt = true;
                //为图像选择一个筛选器
                    saveDlg.Filter = "BMP文件(*.bmp)|*.bmp|" + "Gif文件(*.gif)|*.gif|" + "JPEG文件(*.jpg)|*.jpg|" + "PNG文件(*.png)|*.png";
                //启用“帮助”按钮
                    saveDlg.ShowHelp = true;
    
                //如果选择了格式,则保存图像
                if (saveDlg.ShowDialog() == DialogResult.OK)
                {
                    //获取用户选择的文件名
                    string filename = saveDlg.FileName;
                    string strFilExtn = filename.Remove(0, filename.Length - 3);
    
                    //保存文件
                    switch (strFilExtn)
                    {
                        //以指定格式保存
                        case "bmp":
                            curBitmpap.Save(filename, System.Drawing.Imaging.ImageFormat.Bmp);
                            break;
                        case "jpg":
                            curBitmpap.Save(filename, System.Drawing.Imaging.ImageFormat.Jpeg);
                            break;
                        case "gif":
                            curBitmpap.Save(filename, System.Drawing.Imaging.ImageFormat.Gif);
                            break;
                            case "tif":
                            curBitmpap.Save(filename, System.Drawing.Imaging.ImageFormat.Tiff);
                            break;
                        case "png":
                            curBitmpap.Save(filename, System.Drawing.Imaging.ImageFormat.Png);
                            break;
                        default:
                            break;
                    }
                }
            }
    
            //关闭窗体 
            private void close_Click(object sender, EventArgs e)
            {
                this.Close();
            }
    
            /// <summary>
            /// 提取像素法
            /// </summary>
            private void pixel_Click(object sender, EventArgs e)
            {
                //启动计时器
                myTimer.Start();
                if (curBitmpap != null)
                {
                    Color curColor;
                    int ret;
    
                    //二维图像数组循环
                    for(int i = 0; i < curBitmpap.Width; i++)
                    {
                        for(int j = 0; j < curBitmpap.Height; j++)
                        {
                            //获取该像素点的RGB颜色值
                            curColor = curBitmpap.GetPixel(i, j);
                            //利用公式计算灰度值
                            ret = (int)(curColor.R * 0.299 + curColor.G * 0.587 + curColor.B * 0.114);
                            //设置该像素点的灰度值,R=G=B=ret
                            curBitmpap.SetPixel(i, j, Color.FromArgb(ret, ret, ret));
                        }
                    }
                    //关闭计时器
                    myTimer.Stop();
                    //在TextBox内显示计时时间
                    timeBox.Text = myTimer.Duration.ToString("####.##") + "毫秒";
                    //对窗体进行重新绘制,这将强制执行Paint事件处理程序
                    Invalidate();
                }
            }
    
            /// <summary>
            /// 内存法(适用于任意大小的24位彩色图像)
            /// </summary>
            private void memory_Click(object sender, EventArgs e)
            {
                //启动计时器
                myTimer.Start();
                if (curBitmpap != null)
                {
                    //位图矩形
                    Rectangle rect = new Rectangle(0, 0, curBitmpap.Width, curBitmpap.Height);
                    //以可读写的方式锁定全部位图像素
                    System.Drawing.Imaging.BitmapData bmpData = curBitmpap.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, curBitmpap.PixelFormat);
                    //得到首地址
                    IntPtr ptr = bmpData.Scan0;
    
                    //定义被锁定的数组大小,由位图数据与未用空间组成的
                    int bytes = bmpData.Stride * bmpData.Height;
                    //定义位图数组
                    byte[] rgbValues = new byte[bytes];
                    //复制被锁定的位图像素值到该数组内
                    System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, bytes);
    
                    //灰度化
                    double colorTemp = 0;
                    for (int i = 0; i < bmpData.Height; i++)
                    {
                        //只处理每行中是图像像素的数据,舍弃未用空间
                        for (int j = 0; j < bmpData.Width * 3; j += 3)
                        {
                            //利用公式计算灰度值
                            colorTemp = rgbValues[i * bmpData.Stride + j + 2] * 0.299 + rgbValues[i * bmpData.Stride + j + 1] * 0.587 + rgbValues[i * bmpData.Stride + j] * 0.114;
                            //R=G=B
                            rgbValues[i * bmpData.Stride + j] = rgbValues[i * bmpData.Stride + j + 1] = rgbValues[i * bmpData.Stride + j + 2] = (byte)colorTemp;
                        }
                    }
    
                    //把数组复制回位图
                    System.Runtime.InteropServices.Marshal.Copy(rgbValues, 0, ptr, bytes);
                    //解锁位图像素
                    curBitmpap.UnlockBits(bmpData);
                    //关闭计时器
                    myTimer.Stop();
                    //在TextBox内显示计时时间
                    timeBox.Text = myTimer.Duration.ToString("####.##") + "毫秒";
                    //对窗体进行重新绘制,这将强制执行Paint事件处理程序
                    Invalidate();
                }
            }
    
            /// <summary>
            /// 指针法
            /// </summary>
            private void pointer_Click(object sender, EventArgs e)
            {
                //启动计时器
                myTimer.Start();
                if (curBitmpap != null)
                {
                    //位图矩形
                    Rectangle rect = new Rectangle(0, 0, curBitmpap.Width, curBitmpap.Height);
                    //以可读写的方式锁定全部位图像素
                    System.Drawing.Imaging.BitmapData bmpData = curBitmpap.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, curBitmpap.PixelFormat);
    
                    byte temp = 0;
                    //启用不安全模式
                    unsafe
                    {
                        //得到首地址
                        byte* ptr = (byte*)(bmpData.Scan0);
                        //二维图像循环
                        for (int i = 0; i < bmpData.Height; i++)
                        {
                            for (int j = 0; j < bmpData.Width; j++)
                            {
                                //利用公式计算灰度值
                                temp = (byte)(0.299 * ptr[2] + 0.587 * ptr[1] + 0.114 * ptr[0]);
                                //R=G=B
                                ptr[0] = ptr[1] = ptr[2] = temp;
                                //指向下一个像素
                                ptr += 3;
                            }
                            //指向下一行数组的首个字节
                            ptr += bmpData.Stride - bmpData.Width * 3;
                        }
                    }
                    //解锁位图像素
                    curBitmpap.UnlockBits(bmpData);
                    //关闭计时器
                    myTimer.Stop();
                    //在TextBox内显示计时时间
                    timeBox.Text = myTimer.Duration.ToString("####.##") + "毫秒";
                    //对窗体进行重新绘制,这将强制执行Paint事件处理程序
                    Invalidate();
                }
            }
    
            /// <summary>
            /// 内存法(仅适用于512*512的图像)
            /// </summary>
            //private void memory_Click(object sender, EventArgs e)
            //{
            //    if (curBitmpap != null)
            //    {
            //        //位图矩形
            //        Rectangle rect = new Rectangle(0, 0, curBitmpap.Width, curBitmpap.Height);
            //        //以可读写的方式锁定全部位图像素
            //        System.Drawing.Imaging.BitmapData bmpData = curBitmpap.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, curBitmpap.PixelFormat);
            //        //得到首地址
            //        IntPtr ptr = bmpData.Scan0;
    
            //        //24位bmp位图字节数
            //        int bytes = curBitmpap.Width * curBitmpap.Height * 3;
            //        //定义位图数组
            //        byte[] rgbValues = new byte[bytes];
            //        //复制被锁定的位图像素值到该数组内
            //        System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, bytes);
    
            //        //灰度化
            //        double colorTemp = 0;
            //        for(int i = 0; i < rgbValues.Length; i += 3)
            //        {
            //            //利用公式计算灰度值
            //            colorTemp = rgbValues[i + 2] * 0.299 + rgbValues[i + 1] * 0.587 + rgbValues[i] * 0.114;
            //            //R=G=B
            //            rgbValues[i]=rgbValues[i+1]=rgbValues[i+2]=(byte)colorTemp;
            //        }
    
            //        //把数组复制回位图
            //        System.Runtime.InteropServices.Marshal.Copy(rgbValues, 0, ptr, bytes);
            //        //解锁位图像素
            //        curBitmpap.UnlockBits(bmpData);
            //        //对窗体进行重新绘制,这将强制执行Paint事件处理程序
            //        Invalidate();
            //    }
            //}
    
    
    
        }
    }

     

    /// <summary>
          /// 图像灰度化
          /// </summary>
          /// <param name="bmp"></param>
          /// <returns></returns>
          public static Bitmap ToGray(Bitmap bmp)
          {
              for (int i = 0; i < bmp.Width; i++)
              {
                  for (int j = 0; j < bmp.Height; j++)
                  {
                      //获取该点的像素的RGB的颜色
                      Color color = bmp.GetPixel(i, j);
                      //利用公式计算灰度值
                      int gray = (int)(color.R * 0.3 + color.G * 0.59 + color.B * 0.11);
                      Color newColor = Color.FromArgb(gray, gray, gray);
                      bmp.SetPixel(i, j, newColor);
                  }
              }
              return bmp;
          }

     

     

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Runtime.InteropServices;
    using System.ComponentModel;
    using System.Threading;
    
    namespace gray
    {
        internal class HiPerfTimer
        {
            //引用win32API中的QueryPerformanceCounter()方法
            //该方法用来查询任意时刻高精度计数器的实际值
            [DllImport("Kernel32.dll")]         //using System.Runtime.InteropServices;
            private static extern bool QueryPerformanceCounter(out long lpPerformanceCount);
    
            //引用win32API中的QueryPerformanceCounter()方法
            //该方法用来查询任意时刻高精度计数器的实际值
            [DllImport("Kernel32.dll")]
            private static extern bool QueryPerformanceFrequency(out long lpFrequency);
    
            private long startTime, stopTime;
            private long freq;
    
            public HiPerfTimer()
            {
                startTime = 0;
                stopTime = 0;
    
                if(QueryPerformanceFrequency(out freq) == false)
                {
                    //不支持高性能计时器
                    throw new Win32Exception();     //using System.ComponentModel;
                }
            }
    
            //开始计时
            public void Start()
            {
                //让等待线程工作
                Thread.Sleep(0);                //using System.Threading;
    
                QueryPerformanceCounter(out startTime);
            }
            //结束计时
            public void Stop()
            {
                QueryPerformanceCounter(out stopTime);
            }
            //返回计时结果(ms)
            public double Duration
            {
                get
                {
                    return (double)(stopTime - startTime) * 1000 / (double)freq;
                }
            }
    
        }
    }

     

    灰度图像二值化
    在进行了灰度化处理之后,图像中的每个象素只有一个值,那就是象素的灰度值。它的大小决定了象素的亮暗程度。为了更加便利的开展下面的图像处理操作,还需要对已经得到的灰度图像做一个二值化处理。图像的二值化就是把图像中的象素根据一定的标准分化成两种颜色。在系统中是根据象素的灰度值处理成黑白两种颜色。和灰度化相似的,图像的二值化也有很多成熟的算法。它可以采用自适应阀值法,也可以采用给定阀值法。

         #region Otsu阈值法二值化模块   
    
            /// <summary>   
            /// Otsu阈值   
            /// </summary>   
            /// <param name="b">位图流</param>   
            /// <returns></returns>   
            public Bitmap OtsuThreshold(Bitmap b)
            {
                // 图像灰度化   
                // b = Gray(b);   
                int width = b.Width;
                int height = b.Height;
                byte threshold = 0;
                int[] hist = new int[256];
    
                int AllPixelNumber = 0, PixelNumberSmall = 0, PixelNumberBig = 0;
    
                double MaxValue, AllSum = 0, SumSmall = 0, SumBig, ProbabilitySmall, ProbabilityBig, Probability;
                BitmapData data = b.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
                unsafe
                {
                    byte* p = (byte*)data.Scan0;
                    int offset = data.Stride - width * 4;
                    for (int j = 0; j < height; j++)
                    {
                        for (int i = 0; i < width; i++)
                        {
                            hist[p[0]]++;
                            p += 4;
                        }
                        p += offset;
                    }
                    b.UnlockBits(data);
                }
                //计算灰度为I的像素出现的概率   
                for (int i = 0; i < 256; i++)
                {
                    AllSum += i * hist[i];     //   质量矩   
                    AllPixelNumber += hist[i];  //  质量       
                }
                MaxValue = -1.0;
                for (int i = 0; i < 256; i++)
                {
                    PixelNumberSmall += hist[i];
                    PixelNumberBig = AllPixelNumber - PixelNumberSmall;
                    if (PixelNumberBig == 0)
                    {
                        break;
                    }
    
                    SumSmall += i * hist[i];
                    SumBig = AllSum - SumSmall;
                    ProbabilitySmall = SumSmall / PixelNumberSmall;
                    ProbabilityBig = SumBig / PixelNumberBig;
                    Probability = PixelNumberSmall * ProbabilitySmall * ProbabilitySmall + PixelNumberBig * ProbabilityBig * ProbabilityBig;
                    if (Probability > MaxValue)
                    {
                        MaxValue = Probability;
                        threshold = (byte)i;
                    }
                }
                return this.Threshoding(b, threshold);
            } // end of OtsuThreshold 2  
            #endregion
    
            #region      固定阈值法二值化模块
            public Bitmap Threshoding(Bitmap b, byte threshold)
            {
                int width = b.Width;
                int height = b.Height;
                BitmapData data = b.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
                unsafe
                {
                    byte* p = (byte*)data.Scan0;
                    int offset = data.Stride - width * 4;
                    byte R, G, B, gray;
                    for (int y = 0; y < height; y++)
                    {
                        for (int x = 0; x < width; x++)
                        {
                            R = p[2];
                            G = p[1];
                            B = p[0];
                            gray = (byte)((R * 19595 + G * 38469 + B * 7472) >> 16);
                            if (gray >= threshold)
                            {
                                p[0] = p[1] = p[2] = 255;
                            }
                            else
                            {
                                p[0] = p[1] = p[2] = 0;
                            }
                            p += 4;
                        }
                        p += offset;
                    }
                    b.UnlockBits(data);
                    return b;
    
                }
    
            }
            #endregion

     

    转载于:https://www.cnblogs.com/dearzhoubi/p/8571652.html

    展开全文
  • 内有下载链接 图像识别:图像灰度化二值化图像识别:图像灰度化二值化
  • C++——bmp图像灰度化+二值化

    千次阅读 2018-05-11 21:18:56
    本文实现bmp图像灰度化二值化操作:1、灰度化2、二值化 图像二值化处理就是将图像上的点的灰度置为0或255,也就是讲整个图像呈现出明显的黑白效果。即将256个亮度等级的灰度图像通过适当的阀值选取而获得仍然...

    本文实现bmp图像的灰度化及二值化操作:

    1、灰度化

           对于彩色转灰度,有一个很著名的心理学公式:

                              Gray = R*0.299 + G*0.587 + B*0.114

    而实际应用时,希望避免低速的浮点运算,所以需要整数算法。
      注意到系数都是3位精度的没有,我们可以将它们缩放1000倍来实现整数运算算法:
                              Gray = (R*299 + G*587 + B*114 + 500) / 1000
      RGB一般是8位精度,现在缩放1000倍,所以上面的运算是32位整型的运算。注意后面那个除法是整数除法,所以需要加上500来实现四舍五入。
      就是由于该算法需要32位运算,所以该公式的另一个变种很流行:
                              Gray = (R*30 + G*59 + B*11 + 50) / 100

      但是,虽说上一个公式是32位整数运算,但是根据80x86体系的整数乘除指令的特点,是可以用16位整数乘除指令来运算的。而且现在32位早普及了(AMD64都出来了),所以推荐使用上一个公式。

           上面的整数算法已经很快了,但是有一点仍制约速度,就是最后的那个除法。移位比除法快多了,所以可以将系数缩放成 2的整数幂。
      习惯上使用16位精度,2的16次幂是65536,所以这样计算系数:
                              0.299 * 65536 = 19595.264 ≈ 19595
                              0.587 * 65536 + (0.264) = 38469.632 + 0.264 = 38469.896 ≈ 38469
                              0.114 * 65536 + (0.896) =   7471.104 + 0.896 = 7472
      可能很多人看见了,我所使用的舍入方式不是四舍五入。四舍五入会有较大的误差,应该将以前的计算结果的误差一起计算进去,舍入方式是去尾法:
      写成表达式是:
                             Gray = (R*19595 + G*38469 + B*7472) >> 16
      2至20位精度的系数:
                              Gray = (R*1 + G*2 + B*1) >> 2
                              Gray = (R*2 + G*5 + B*1) >> 3
                              Gray = (R*4 + G*10 + B*2) >> 4
                              Gray = (R*9 + G*19 + B*4) >> 5
                              Gray = (R*19 + G*37 + B*8) >> 6
                              Gray = (R*38 + G*75 + B*15) >> 7
                              Gray = (R*76 + G*150 + B*30) >> 8
                              Gray = (R*153 + G*300 + B*59) >> 9
                              Gray = (R*306 + G*601 + B*117) >> 10
                              Gray = (R*612 + G*1202 + B*234) >> 11
                              Gray = (R*1224 + G*2405 + B*467) >> 12
                              Gray = (R*2449 + G*4809 + B*934) >> 13
                              Gray = (R*4898 + G*9618 + B*1868) >> 14
                              Gray = (R*9797 + G*19235 + B*3736) >> 15
                              Gray = (R*19595 + G*38469 + B*7472) >> 16
                              Gray = (R*39190 + G*76939 + B*14943) >> 17
                              Gray = (R*78381 + G*153878 + B*29885) >> 18
                              Gray = (R*156762 + G*307757 + B*59769) >> 19

                              Gray = (R*313524 + G*615514 + B*119538) >> 20

    灰度化处理有很多方式,本文仅选用一种。

    2、二值化

           图像的二值化处理就是将图像上的点的灰度置为0或255,也就是讲整个图像呈现出明显的黑白效果。即将256个亮度等级的灰度图像通过适当的阀值选取而获得仍然可以反映图像整体和局部特征的二值化图像。所有灰度大于或等于阀值的像素被判定为属于特定物体,其灰度值为255表示,否则这些像素点被排除在物体区域以外,灰度值为0,表示背景或者例外的物体区域。

    void img_rgb2gray()
    {
    
    	char readPath[] = "D:\\C++_file\\image_deal_C++\\IMAGE_JIEQU\\1.bmp";
    	readBmp(readPath);
    
    	
    	unsigned char *pGrayData;
    	//因为转换后多了个颜色表,所以要改变
    	bfoffbits += (sizeof(RGBQUAD) * 256);
    	//biSizeImg存储的为位图数据占用的字节数,转换为灰度图像后值发生改变,  
    	//因为24为真彩色位图数据的一个像素用3各字节表示,灰度图像为1个字节  
    	biBitCount = 8;
    	int lineBytes = (bmpWidth * biBitCount / 8 + 3) / 4 * 4;
    	int oldLineBytes = (bmpWidth * 24 / 8 + 3) / 4 * 4;;
    	pGrayData = new unsigned char[lineBytes * bmpHeight];
    	//memset(pGrayData, 0, bmpInfoHeader.biSizeImage);
    	//这里要注意,Windows规定一个扫描行所占的字节数必须是  
    	//4的倍数(即以long为单位),不足的以0填充,所以如果当前biWidth如果不是  
    	//4的倍数时,要在后面补0直到为4的倍数  
    	//-------------------------------定义灰度图像的颜色表--------------------//  
    	
    	pColorTable = new RGBQUAD[256];
    	for (int i = 0; i < 256; i++)
    	{
    		(*(pColorTable + i)).rgbBlue = i;
    		(*(pColorTable + i)).rgbGreen = i;
    		(*(pColorTable + i)).rgbRed = i;
    		(*(pColorTable + i)).rgbReserved = 0;
    	}
    	//--------------------------------将RGB转换为灰度值------------------------//  
    	int red, green, blue;
    	BYTE gray;
    	//char gray_1;
    
    	for (int i = 0; i < bmpHeight; i++)
    	{
    		//位图数据(pBmpData)中存储的实际像素数为biWidth个,而一个扫描行要lineByte个字节,  
    		//多余出来的是上面补的0,所以要转换的要是实际的像素数,  
    		//因为转换前后biWidth是相同的,而lineByte是不同的,也就是后面补的0不同  
    		for (int j = 0; j < bmpWidth; j++)
    		{
    			red = *(pBmpBuf + i*oldLineBytes + 3 * j + 2);
    			green = *(pBmpBuf + i*oldLineBytes + 3 * j + 1);
    			blue = *(pBmpBuf + i*oldLineBytes + 3 * j );
    			gray = (BYTE)((77 * red + 151 * green + 28 * blue) >> 8);
    			//gray_1 = red*0.299 + green*0.587 + blue*0.114;
    			*(pGrayData + i*lineBytes + j) = gray;
    		}
    	}
    	/*
    	int threshold=128;
    	for (int i = 0; i < bmpHeight; i++)
    	{
    		//二值化 
    		for (int j = 0; j < bmpWidth; j++)
    		{
    			if (*(pGrayData + i*lineBytes + j)>threshold)
    				*(pGrayData + i*lineBytes + j) = 255;
    			else
    				*(pGrayData + i*lineBytes + j) = 0;
    		}
    	}
    	*/
    	char writePath[] = "D:\\C++_file\\image_deal_C++\\IMAGE_JIEQU\\11.bmp";
    	saveBmp(writePath, pGrayData, bmpWidth, bmpHeight, biBitCount, pColorTable);
    	printf("灰度化完成,请查看bmp文件。\n\n");
    }


    展开全文
  • opencv实现图像灰度化二值化

    热门讨论 2011-03-04 14:57:32
    基于开源的opencv,实现一个图像灰度化二值化。用于后续的图像分割和识别
  • 本篇文章是对c#图像灰度化、灰度反转、二值化的实现方法进行了详细的分析介绍,需要的朋友参考下
  • 图像灰度化二值化在图像识别里面经常使用,这里以HLS实现整个过程 一、实现功能: 读取一张bmp图片,输出一张灰度化bmp图片和二值化后的黑白图片 二、需要用到的接口 1、读写图片工具函数bmp_tools.cpp 这里我们用...
  • c#图像处理之图形灰度化二值化处理。通过读取图像,实现图像灰度化,二值化功能,并保存。
  • 主要介绍了Android实现图像灰度化、线性灰度变化和二值化处理方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
  • 本篇将介绍彩色图像灰度化二值化的原理,并使用Python来实现对应算法内容。
  • 灰度图像二值化处理

    2018-06-20 18:11:38
    图像灰度化处理算法,涵盖几种经典二值化算法的实现,如:灰度平均值,黄氏模糊阈值,谷底最小值,等13中二值化阈值选择方法
  • C#和EmguCV实现图像灰度化二值化(VS2010窗体+代码)。学生一枚,虚心接受批评。
  • 图像灰度化: 将彩色图像转化成为灰度图像的过程成为图像的灰度化处理。彩色图像中的每个像素的颜色有R、G、B三个分量决定,而每个分量有255中值可取,这样一个像素点可以有1600多万(255*255*255)的颜色的变化范围...
  • 图像灰度化方法1:求出每个像素点的RGB三个分量的平均,然后将这个平均赋予给这个像素的三个分量 方法2:求RGB和YUV颜色空间的变化关系,建立亮度Y与RGB三个颜色分量的对应关系:Y=0.3R+0.59G+0.11B,以这个...
  • 1、灰度化 ## 自动补齐代码 %config IPComplter.greedy=True ## 获取图片&显示图片 from PIL import Image import matplotlib.pyplot as plt import numpy as np #获取图片 def getimg(): return Image.open...
  • c#图像处理 图像预处理 灰度化 二值化 提取像素法 内存法 指针法 灰度化方法:最小值 最大值 加权平均法 二值化方法: 固定值 平均值 Bernsen算法
  • 图像灰度化+二值化+直方图   本文主要用于记录将彩色图像转换成灰度图,分别计算彩色图像各个通道以及灰度图的直方图,将各个通道以及灰度图分别二值化并显示结果。 文章目录1 处理流程2 准备知识2.1 彩色图像...
  • 这是一款实现图像灰度二值化处理功能源码,该源码主要是利用opencv2.framework进行图像灰度二值化处理,可以对图像的某个特定矩形区域进行二值化处理,效果如图所示,上方图片是原图,下方是对上方的图片的某个...
  • Opencv-图像灰度化二值化

    千次阅读 2014-04-03 11:47:54
    图像灰度化:将彩色图像转化成为灰度图像的过程成为图像的灰度化处理。彩色图像中的每个像素的颜色有R、G、B三个分量决定,而每个分量像素在0~255,这样一个像素点可以有1600多万(255*255*255)的颜色的变化范围...
  • 灰度图像二值化方法研究,灰度图像二值化方法研究,灰度图像二值化方法研究,灰度图像二值化方法研究
  • 本篇主要讲述32位彩色图像灰度化二值化内容,通过简单的C语言实现,来帮助初学者一学即会,融会贯通。
  • 灰度图像二值化

    2013-11-14 16:05:39
    这是一个基于OpenCV的灰度图像二值化程序,可移植性强,运行完全没有问题,注意显示的图片路径根据需要更改一下。。。
  • 灰度图像二值化 一、知识简介 图像二值化( Image Binarization)就是将图像上的像素点的灰度值设置为0或255,也就是将整个图像呈现出明显的黑白效果的过程。 在数字图像处理中,二值图像占有非常重要的地位,图像...
  • #1、读取图像,并把图像转换为灰度图像并显示 import cv2 im = cv2.imread("cat.jpg") #读取图片 im_gray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY) #转换了灰度化 ...#2、固定阈值二值化 retval, im_at_...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 3,324
精华内容 1,329
关键字:

图像灰度化二值化