热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

C#数字图像处理的3种方法

来源:http:zxlovenet.cnblogs.com本文主要通过彩色图象灰度化来介绍C#处理数字图像的3种方法,Bitmap类、BitmapData类和Graphics类是C

来源: http://zxlovenet.cnblogs.com 

本文主要通过彩色图象灰度化来介绍C#处理数字图像的3种方法,Bitmap类、BitmapData类和Graphics类是C#处理图像的的3个重要的类。

Bitmap只要用于处理由像素数据定义的图像的对象,主要方法和属性如下:

         GetPixel方法和SetPixel方法,获取和设置一个图像的指定像素的颜色。

         PixelFormat属性,返回图像的像素格式。

         Palette属性,获取或折纸图像所使用的颜色调色板。

         Height属性和Width属性,返回图像的高度和宽度。

         LockBits方法和UnlockBits方法,分别锁定和解锁系统内存中的位图像素。

BitmapData对象指定了位图的属性:

         Height属性,被锁定位图的高度。

         Width属性,被锁定位图的宽度。

         PixelFormat属性,数据的实际像素格式。

         Scan0属性,被锁定数组的首字节地址。

         Stride属性,步幅,也称扫描宽度。

彩色图象灰度化

24位彩色图象每个像素用3个字节表示,每个字节对应着R、G、B分量的亮度(红、绿、蓝)。当3个分量不想同时表现为灰度图像。下面有三种转换公式:

技术分享

Gray(I,j)为转换后的灰度图像在(I,j)点出的灰度值。由于人眼对颜色的感应不同,有了下面的转换公式:

技术分享

观察发现绿色所占比重最大,所以转换时直接使用G值作为转换结果:

技术分享

图像处理的3种方法分别是:提取像素法、内存法和指针法,它们各自有各自的特点。

提取像素法

使用的是GDI+中的Bitmap.GetPixel和Bitmap.SetPixel方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
if (bitmap != null)
{
    newbitmap = bitmap.Clone() as Bitmap;
    Color pixel;
    int ret;
    for (int x = 0; x
    {
        for (int y = 0; y
        {
            pixel = newbitmap.GetPixel(x, y);
            ret = (int)(pixel.R * 0.299 + pixel.G * 0.587 + pixel.B * 0.114);
            newbitmap.SetPixel(x, y, Color.FromArgb(ret, ret, ret));
        }
    }
    pictureBox1.Image = newbitmap.Clone() as Image;
}

内存法

内存法是把图像数据直接复制到内存中,这样程序的运行速度就能大大提高了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
if (bitmap != null)
{
    newbitmap = bitmap.Clone() as Bitmap;
    Rectangle rect = new Rectangle(0, 0, newbitmap.Width, newbitmap.Height);
    System.Drawing.Imaging.BitmapData bmpdata = newbitmap.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, newbitmap.PixelFormat);
    IntPtr ptr = bmpdata.Scan0;
 
    int bytes = newbitmap.Width * newbitmap.Height * 3;
    byte[] rgbvalues = new byte[bytes];
 
    System.Runtime.InteropServices.Marshal.Copy(ptr, rgbvalues, 0, bytes);
 
    double colortemp = 0;
    for (int i = 0; i
    {
        colortemp = rgbvalues[i + 2] * 0.299 + rgbvalues[i + 1] * 0.587 + rgbvalues[i] * 0.114;
        rgbvalues[i] = rgbvalues[i + 1] = rgbvalues[i + 2] = (byte)colortemp;
    }
 
    System.Runtime.InteropServices.Marshal.Copy(rgbvalues, 0, ptr, bytes);
 
    newbitmap.UnlockBits(bmpdata);
    pictureBox1.Image = newbitmap.Clone() as Image;
}

指针法

这个方法和内存法相似,开始都是通过LockBits方法来获取位图的首地址,这个方法更简洁,直接用指针进行位图操作。所以对内存的操作需要在unsafe下进行操作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
if (bitmap != null)
{
    newbitmap = bitmap.Clone() as Bitmap;
    Rectangle rect = new Rectangle(0, 0, newbitmap.Width, newbitmap.Height);
    System.Drawing.Imaging.BitmapData bmpdata = newbitmap.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, newbitmap.PixelFormat);
    byte temp;
 
    unsafe
    {
        byte* ptr = (byte*)(bmpdata.Scan0);
 
        for (int x = 0; x
        {
            for (int y = 0; y
            {
                temp = (byte)(0.299 * ptr[2] + 0.587 * ptr[1] + 0.114 * ptr[0]);
                ptr[0] = ptr[1] = ptr[2] = temp;
                ptr += 3;
            }
            ptr += bmpdata.Stride - bmpdata.Width * 3;
        }
    }
 
    newbitmap.UnlockBits(bmpdata);
    pictureBox1.Image = newbitmap.Clone() as Image;
}

3种方法的比较

 技术分享

比较一下可以得出结论,提取像素法比较简单,但是效率比较低;内存法效率有了很大的提高,但是代码比较复杂;指针法效率比内存法更高一些,但是不安全。综上比较结果内存法比较好,效率即高又能发挥C#安全的优点。

C#数字图像处理的3种方法


推荐阅读
  • Redis底层数据结构之压缩列表的介绍及实现原理
    本文介绍了Redis底层数据结构之压缩列表的概念、实现原理以及使用场景。压缩列表是Redis为了节约内存而开发的一种顺序数据结构,由特殊编码的连续内存块组成。文章详细解释了压缩列表的构成和各个属性的含义,以及如何通过指针来计算表尾节点的地址。压缩列表适用于列表键和哈希键中只包含少量小整数值和短字符串的情况。通过使用压缩列表,可以有效减少内存占用,提升Redis的性能。 ... [详细]
  • 本文介绍了使用Java实现大数乘法的分治算法,包括输入数据的处理、普通大数乘法的结果和Karatsuba大数乘法的结果。通过改变long类型可以适应不同范围的大数乘法计算。 ... [详细]
  • 本文介绍了C#中数据集DataSet对象的使用及相关方法详解,包括DataSet对象的概述、与数据关系对象的互联、Rows集合和Columns集合的组成,以及DataSet对象常用的方法之一——Merge方法的使用。通过本文的阅读,读者可以了解到DataSet对象在C#中的重要性和使用方法。 ... [详细]
  • 1,关于死锁的理解死锁,我们可以简单的理解为是两个线程同时使用同一资源,两个线程又得不到相应的资源而造成永无相互等待的情况。 2,模拟死锁背景介绍:我们创建一个朋友 ... [详细]
  • 动态规划算法的基本步骤及最长递增子序列问题详解
    本文详细介绍了动态规划算法的基本步骤,包括划分阶段、选择状态、决策和状态转移方程,并以最长递增子序列问题为例进行了详细解析。动态规划算法的有效性依赖于问题本身所具有的最优子结构性质和子问题重叠性质。通过将子问题的解保存在一个表中,在以后尽可能多地利用这些子问题的解,从而提高算法的效率。 ... [详细]
  • 猜字母游戏
    猜字母游戏猜字母游戏——设计数据结构猜字母游戏——设计程序结构猜字母游戏——实现字母生成方法猜字母游戏——实现字母检测方法猜字母游戏——实现主方法1猜字母游戏——设计数据结构1.1 ... [详细]
  • 本文介绍了lua语言中闭包的特性及其在模式匹配、日期处理、编译和模块化等方面的应用。lua中的闭包是严格遵循词法定界的第一类值,函数可以作为变量自由传递,也可以作为参数传递给其他函数。这些特性使得lua语言具有极大的灵活性,为程序开发带来了便利。 ... [详细]
  • 基于layUI的图片上传前预览功能的2种实现方式
    本文介绍了基于layUI的图片上传前预览功能的两种实现方式:一种是使用blob+FileReader,另一种是使用layUI自带的参数。通过选择文件后点击文件名,在页面中间弹窗内预览图片。其中,layUI自带的参数实现了图片预览功能。该功能依赖于layUI的上传模块,并使用了blob和FileReader来读取本地文件并获取图像的base64编码。点击文件名时会执行See()函数。摘要长度为169字。 ... [详细]
  • HDU 2372 El Dorado(DP)的最长上升子序列长度求解方法
    本文介绍了解决HDU 2372 El Dorado问题的一种动态规划方法,通过循环k的方式求解最长上升子序列的长度。具体实现过程包括初始化dp数组、读取数列、计算最长上升子序列长度等步骤。 ... [详细]
  • 本文介绍了通过ABAP开发往外网发邮件的需求,并提供了配置和代码整理的资料。其中包括了配置SAP邮件服务器的步骤和ABAP写发送邮件代码的过程。通过RZ10配置参数和icm/server_port_1的设定,可以实现向Sap User和外部邮件发送邮件的功能。希望对需要的开发人员有帮助。摘要长度:184字。 ... [详细]
  • Java验证码——kaptcha的使用配置及样式
    本文介绍了如何使用kaptcha库来实现Java验证码的配置和样式设置,包括pom.xml的依赖配置和web.xml中servlet的配置。 ... [详细]
  • 高质量SQL书写的30条建议
    本文提供了30条关于优化SQL的建议,包括避免使用select *,使用具体字段,以及使用limit 1等。这些建议是基于实际开发经验总结出来的,旨在帮助读者优化SQL查询。 ... [详细]
  • 本文介绍了指针的概念以及在函数调用时使用指针作为参数的情况。指针存放的是变量的地址,通过指针可以修改指针所指的变量的值。然而,如果想要修改指针的指向,就需要使用指针的引用。文章还通过一个简单的示例代码解释了指针的引用的使用方法,并思考了在修改指针的指向后,取指针的输出结果。 ... [详细]
  • 在project.properties添加#Projecttarget.targetandroid-19android.library.reference.1..Sliding ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
author-avatar
晴天逍遥
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有