`
itjavagoodqq
  • 浏览: 37209 次
文章分类
社区版块
存档分类
最新评论

[转]使用c#进行图像处理的几种方法

    博客分类:
  • java
阅读更多
    <p><a target="_blank">本文转自:<font><a href="http://conner-wang.spaces.live.com/blog/cns!568d1f7f9d97c059!488.entry">http://conner-wang.spaces.live.com/blog/cns!568d1f7f9d97c059!488.entry</a></font>本文讨论了c#图像处理中bitmap类、bitmapdata类和unsafe代码的使用以及字节对齐问题。 <font color="#ff8000"><strong>bitmap类</strong></font> <font color="#0080ff">命名空间:system.drawing</font> <font color="#0080ff">封装 gdi+ 位图,此位图由图形图像及其属性的像素数据组成。bitmap 是用于处理由像素数据定义的图像的对象。</font>  利用c#类进行图像处理,最方便的是使用bitmap类,使用该类的getpixel()与setpixel()来访问图像的每个像素点。下面是msdn中的示例代码:<blockquote><font color="#8000ff">public void getpixel_example(painteventargs e) <br>{ <br> // create a bitmap object from an image file. <br> bitmap mybitmap = new bitmap("grapes.jpg"); <br> // get the color of a pixel within mybitmap. <br> color pixelcolor = mybitmap.getpixel(50, 50); <br> // fill a rectangle with pixelcolor. <br> solidbrush pixelbrush = new solidbrush(pixelcolor); <br> e.graphics.fillrectangle(pixelbrush, 0, 0, 100, 100); <br>}</font> </blockquote> 可见,bitmap类使用一种优雅的方式来操作图像,但是带来的性能的降低却是不可忽略的。比如对一个800*600的彩色图像灰度化,其耗费的时间都要以秒为单位来计算。在实际项目中进行图像处理,这种速度是决对不可忍受的。  <font color="#ff8000"><strong>bitmapdata类</strong></font> <font color="#0080ff">命名空间:system.drawing.imaging</font> <font color="#0080ff">指定位图图像的属性。bitmapdata 类由 bitmap 类的 lockbits 和 unlockbits 方法使用。不可继承。</font>  好在我们还有bitmapdata类,通过bitmapdata bitmapdata lockbits ( )可将 bitmap 锁定到系统内存中。该类的公共属性有:<ul><li>width 获取或设置 bitmap 对象的像素宽度。这也可以看作是一个扫描行中的像素数。</li>    <li>height 获取或设置 bitmap 对象的像素高度。有时也称作扫描行数。</li>    <li>pixelformat 获取或设置返回此 bitmapdata 对象的 bitmap 对象中像素信息的格式。</li>    <li>scan0 获取或设置位图中第一个像素数据的地址。它也可以看成是位图中的第一个扫描行。</li>    <li>stride 获取或设置 bitmap 对象的跨距宽度(也称为扫描宽度)。 </li></ul> 下面的msdn中的示例代码演示了如何使用 pixelformat、height、width 和 scan0 属性;lockbits 和 unlockbits 方法;以及 imagelockmode 枚举。<blockquote><font color="#8000ff">private void lockunlockbitsexample(painteventargs e) <br>{ </font><font color="#8000ff"> // create a new bitmap. <br> bitmap bmp = new bitmap("c:\\fakephoto.jpg"); </font><font color="#8000ff"> // lock the bitmap's bits. <br> rectangle rect = new rectangle(0, 0, bmp.width, bmp.height); <br> system.drawing.imaging.bitmapdata bmpdata = <br> bmp.lockbits(rect, system.drawing.imaging.imagelockmode.readwrite, <br> bmp.pixelformat); <br> // get the address of the first line. <br> intptr ptr = bmpdata.scan0; </font><font color="#8000ff"> // declare an array to hold the bytes of the bitmap. <br> // this code is specific to a bitmap with 24 bits per pixels. <br> int bytes = bmp.width * bmp.height * 3; <br> byte[] rgbvalues = new byte[bytes]; </font><font color="#8000ff"> // copy the rgb values into the array. <br> system.runtime.interopservices.marshal.copy(ptr, rgbvalues, 0, bytes); </font><font color="#8000ff"> // set every red value to 255. <br> for (int counter = 0; counter &lt; rgbvalues.length; counter+=3) <br> rgbvalues[counter] = 255; <br> // copy the rgb values back to the bitmap <br> system.runtime.interopservices.marshal.copy(rgbvalues, 0, ptr, bytes); </font><font color="#8000ff"> // unlock the bits. <br> bmp.unlockbits(bmpdata); </font><font color="#8000ff"> // draw the modified image. <br> e.graphics.drawimage(bmp, 0, 150); </font><font color="#8000ff">} </font></blockquote> 上面的代码演示了如何用数组的方式来访问一幅图像,而不在使用低效的getpixel()和setpixel()。  <font color="#ff8000"><strong>unsafe代码</strong></font>  而在实际中上面的做法仍然不能满足我们的要求,图像处理是一种运算量比较大的操作,不同于我们写的一般的应用程序。我们需要的是一种性能可以同c++程序相媲美的图像处理程序。c++是怎么提高效率的呢,答曰:指针。幸运的是.net也允许我们使用指针,只能在非安全代码块中使用指针。何谓非安全代码?  为了保持类型安全,默认情况下,c# 不支持指针运算。不过,通过使用 unsafe 关键字,可以定义可使用指针的不安全上下文。在公共语言运行库 (clr) 中,不安全代码是指无法验证的代码。c# 中的不安全代码不一定是危险的,只是其安全性无法由 clr 进行验证的代码。因此,clr 只对在完全受信任的程序集中的不安全代码执行操作。如果使用不安全代码,由您负责确保您的代码不会引起安全风险或指针错误。不安全代码具有下列属性:<ul><li>方法、类型和可被定义为不安全的代码块。</li>    <li>在某些情况下,通过移除数组界限检查,不安全代码可提高应用程序的性能。</li>    <li>当调用需要指针的本机函数时,需要使用不安全代码。</li>    <li>使用不安全代码将引起安全风险和稳定性风险。</li>    <li>在 c# 中,为了编译不安全代码,必须用 /unsafe 编译应用程序。 </li></ul> 正如《c#语言规范》中所说无论从开发人员还是从用户角度来看,不安全代码事实上都是一种“安全”功能。不安全代码必须用修饰符 unsafe 明确地标记,这样开发人员就不会误用不安全功能,而执行引擎将确保不会在不受信任的环境中执行不安全代码。  以下代码演示如何借助bitmapdata类采用指针的方式来遍历一幅图像,这里的unsafe代码块中的代码就是非安全代码。<blockquote><font color="#8000ff">//创建图像 <br>bitmap image = new bitmap( "c:\\images\\image.gif" ); <br>//获取图像的bitmapdata对像 <br>bitmapdata data = image.lockbits( new rectangle( 0 , 0 , image.width , image.height ) , imagelockmode.readwrite , pixelformat.format24bpprgb ); <br>//循环处理 <br>unsafe <br>{ <br> byte* ptr = ( byte* )( data.scan0 ); <br> for( int i = 0 ; i &lt; data.height ; i ++ ) <br> { <br> for( int j = 0 ; j &lt; data.width ; j ++ ) <br> { <br> // write the logic implementation here <br> ptr += 3; <br> } <br> ptr += data.stride - data.width * 3; <br> } <br>} </font></blockquote> 毫无疑问,采用这种方式是最快的,所以在实际工程中都是采用指针的方式来访问图像像素的。  <font color="#ff8000"><strong>字节对齐问题</strong></font> <br> 上例中ptr += data.stride - data.width * 3,表示跨过无用的区域,其原因是图像数据在内存中存储时是按4字节对齐的,具体解释如下:  假设有一张图片宽度为6,假设是format24bpprgb格式的(每像素3字节,在以下的讨论中,除非特别说明,否则bitmap都被认为是24位rgb)。显然,每一行需要6*3=18个字节存储。对于bitmap就是如此。但对于bitmapdata,虽然data.width还是等于image.width,但大概是出于显示性能的考虑,每行的实际的字节数将变成大于等于它的那个离它最近的4的整倍数,此时的实际字节数就是stride。就此例而言,18不是4的整倍数,而比18大的离18最近的4的倍数是20,所以这个data.stride = 20。显然,当宽度本身就是4的倍数时,data.stride = image.width * 3。  画个图可能更好理解。r、g、b 分别代表3个原色分量字节,bgr就表示一个像素。为了看起来方便我在们每个像素之间插了个空格,实际上是没有的。x表示补足4的倍数而自动插入的字节。为了符合人类的阅读习惯我分行了,其实在计算机内存中应该看成连续的一大段。 |-------stride-----------| <br>|-------width---------| | <br>scan0: <br>bgr bgr bgr bgr bgr bgr xx <br>bgr bgr bgr bgr bgr bgr xx <br>bgr bgr bgr bgr bgr bgr xx <br>. <br>. <br>.  首先用data.scan0找到第0个像素的第0个分量的地址,这个地址指向的是个byte类型,所以当时定义为byte* ptr。行扫描时,在当前指针位置(不妨看成当前像素的第0个颜色分量)连续取出三个值(3个原色分量。注意,0 1 2代表的次序是b g r。在取指针指向的值时,貌似p[n]和p += n再取p[0]是等价的),然后下移3个位置(ptr += 3,看成指到下一个像素的第0个颜色分量)。做过bitmap.width次操作后,就到达了bitmap.width * 3的位置,应该要跳过图中标记为x的字节了(共有stride - width * 3个字节),代码中就是 ptr += datain.stride - datain.width * 3。  通过阅读本文,相信你已经对使用c#进行图像处理可能用到的几种方法有了一个了解。至于采用哪种方式,取决于你的性能要求。其中第一种方式最优雅;第三种方式最快,但不是安全代码;第二种方式取了个折中,保证是安全代码的同时又提高了效率。熟悉c/c++编程的人可能会比较偏向于第三种方式,我个人也比较喜欢第三种方式。 <strong><font color="#ff8000">参考:</font></strong> 1. msdn2005 2. c#语言规范 3. </a><a href="http://www.codersource.net/csharp_image_processing.aspx" target="_blank">basic image processing support in c#</a> 4. <a href="http://blog.csdn.net/ki1381/archive/2007/01/10/1478611.aspx">使用c#的bitmapdata</a> 作者:<a href="http://conner-wang.spaces.live.com/">http://conner-wang.spaces.live.com/</a>转载请注明出处!</p> 
分享到:
评论

相关推荐

    c#数字图像处理处理算法典型实例

    是人民邮电出版社的新书,其中对c#图像处理的几种方法进行了比较,时间方面,本书的代码2、3、4部分的,采用内存法 ,包括平移,旋转,直方图

    老师布置的数字图像处理实验 c#(主要参考c#数字图像算法典型实例)

    Matlab图像处理工具箱的使用 1.A=imread(filename,fmt) 读入图像文件; 2.imwrite(A,filename,fmt)输出图像; 3.imshow(I,n)图像显示; 实验一(B): BMP文件结构分析与可视化编程 1.文件的输入输出; 2.BMP...

    Bitmap类和图像像素值获取方法

    C#下读取、修改位置Bitmap,以及几种不同方法修改位图数据

    图像处理的边缘检测算法(c#)

    个人的经典收藏 图像处理的边缘检测算法 里面有:roberts,sobel,拉普拉斯,prewitt,robinson,kirsch,smoothed等几种算法

    C#开发实例大全(基础卷).软件开发技术联盟(带详细书签) PDF 下载

    主要内容有C#开发环境的使用、C#语言基础应用、字符串处理技术、数组和集合...使用、DataGridView数据控件、自定义用户控件、文件基本操作、文件夹基本操作、文件流操作、加密、解密及解压缩文件、C#与Word互操作、高效...

    c#下实现数字图像的集中常见变换

    数字图像处理系统 根据数字图像处理课上老师布置的作业,用基于c#的.net实现。有几种简单的图像变换,图像直方图等。

    C#全能速查宝典

    分别介绍了C#语言基础、Windows窗体及常用控件、Windows高级控件、控件公共属性、方法及事件、数据库开发、文件、数据流与注册表、GDI+绘图技术和C#高级编程,共包含562个C#编程中常用的属性、方法、类和各种技术,...

    C#编程经验技巧宝典

    ”操作符 22 &lt;br&gt;2.4 表达式与关键词 22 &lt;br&gt;0045 正确使用“&&”和“||” 22 &lt;br&gt;0046 如何处理程序“溢出”错误 23 &lt;br&gt;0047 有效使用base关键字 23 &lt;br&gt;0048 typeof表达式的使用 23...

    医学图像处理及其在制定放疗计划中的应用

    本文首先介绍了医学图像的获取和预处理技术,其中包括DICOM标准、医学 图像的预处理、图像的增强以及图像的几何变换等...度特征,边缘特征提取的几种方法,以及放疗计划制定中针对医学剂量图像的几 种特殊的特征提取。

    C#程序设计经典300例源代码

    主要介绍C#编程中几种常用应用程序的创建方法、基本语法、面向对象的基础知识、程序中常用的数据结构与算法、项目开发中常用的设计模式、Windows窗体编程、多线程的使用、文件系统的管理、注册表技术运用、数据库的...

    图形图像处理(lanxv)

    这是我们本学期上过的一门课程,运用面向对象的方法处理的一些图形图像处理的实验,包括几种平滑,锐化,FFt变换,种子填充和扫描线填充

    C#数据结构

    C#版本数据结构,用C#的同志们有福啦 本书节选: 第1章 绪论 数据是外部世界信息的计算机化,是计算机加工处理的对象。运用计算机处 理数据时,必须解决四个方面的问题:一是如何在计算机中方便、高效地表示和 ...

    C# for CSDN 乱七八糟的看不懂

    C#(WINFORM)学习 一、 C#基础 基础 类型和变量 类型和变量 类型 C# 支持两种类型:“值类型”和“引用类型”。值类型包括简单类型(如 char、int 和 float 等)、枚举类型和结构类型。引用类型包括类 (Class)类 ...

    C#人工智能常见算法介绍

    2. 自然语言处理:自然语言处理(Natural Language Processing, NLP)是研究计算机如何理解和处理人类语言的技术。它涉及对文本、语音和对话的识别、理解、生成和翻译。 3. 计算机视觉:计算机视觉是一种研究计算机...

    高性能图像匹配软件 ImageMatch(卓高职业学校收集)

    用C#开发了一款图像匹配软件,功能如下: 1、实现了SSDA算法 2、实现了小波多尺度图像匹配算法 3、实现了基于粒子群的图像...以及以上几种算法的相互结合 附件大小限制,需要源码的,请联系QQ26471375,友情赠送

    asp.net知识库

    使用.ashx文件处理IHttpHandler实现发送文本及二进制数据的方法 制作一个简单的多页Tab功能 一完美的关于请求的目录不存在而需要url重写的解决方案! 在C#中实现MSN消息框的功能 XmlHttp实现无刷新三联动ListBox 鼠标...

    GTK+2.0+中文教程.pdf

    如果你由于种种原因不喜欢这种方法,还有另外两种使用 GTK 的方法。首先,你 可以只使用 C++ 中的 C 子集来调用 GTK,这样就可以使用本教程描述的 C 接口。其次,你可以用下述方法同时使用 GTK 和 C++:把所 用的回...

Global site tag (gtag.js) - Google Analytics