当前位置:  编程技术>.net/c#/asp.net

c#中实现图片灰度化技术详解

    来源: 互联网  发布时间:2014-11-02

    本文导语:  去年买了本数字图像处理算法,一直都没有看,前几个星期都一直忙着工作上的活,趁这阶段悠闲点,玩一玩图片处理,这玩意还是非常有意思的。 以前我们在做Web上的用户注册时,通常都会做一个验证码,大家都知道用来防...

去年买了本数字图像处理算法,一直都没有看,前几个星期都一直忙着工作上的活,趁这阶段悠闲点,玩一玩图片处理,这玩意还是非常有意思的。

以前我们在做Web上的用户注册时,通常都会做一个验证码,大家都知道用来防止暴力注册的,当然提到验证码大家都知道C#里面有一个Bitmap类专门用来处理图片的,好吧,这一篇我们从最简单的“图片灰度化”说起。

一:图片灰度化

我们都知道,位图是由一个一个像素点组成的,像素点可能是红色,橙色,粉色等等,这些颜色我们都知道是用RGB来表示的。

每个颜色分量都是一个字节(0-255),所以一般情况下图的像素点都是24位,当然还有32位,64位,当RGB是0-255之间的不同值时,那么该像素点就呈现“五颜六色”,而当RGB都是相同的值是,则像素点呈现“灰色”,如果大家玩过CSS的话,肯定都知道给一个字体的color通常都是#999999,#666666,#333333这些不同深度的灰色。

1.计算公式

下面我们该如何设置合理的灰度值呢?当然还是用当前的RGB为模板,然后对RGB乘以一个合理的权重就ok了

代码如下:

   Gary(i,j)=0.299*R(i,j)+0.587*G(i,j)+0.114*B(i,j);

2.编程

有了公式,实现起来就不成问题了。Bitmap类中有一个GetPixel/SetPixel,它可以获取和设置当前的像素点。

static void Main(string[] args)
{
  Bitmap bitmap = new Bitmap(Environment.CurrentDirectory + "//1.jpg");
 
  for (int i = 0; i < bitmap.Width; i++)
  {
    for (int j = 0; j < bitmap.Height; j++)
    {
      //取图片当前的像素点
      var color = bitmap.GetPixel(i, j);
 
      var gray = (int)(color.R * 0.299 + color.G * 0.587 + color.B * 0.114);
 
      //重新设置当前的像素点
      bitmap.SetPixel(i, j, Color.FromArgb(gray, gray, gray));
    }
  }
 
  bitmap.Save(Environment.CurrentDirectory + "//2.jpg");
}

3.改进

上面这个方法很简单,Get/Set就Ok了,当然这是我们站在像素点这个角度来考虑问题的,貌似只要O(N2)的时间就可以KO问题,但是Get/Set远远不是O(1)的,基于性能考虑,我们能不能有更优的方法,此时我们可以站在字节这个角度思考,不过这里我们要注意一个问题就是:比如图片的width=21px,一个像素点占用3个字节,但是21个像素点不一定就占用63个字节,这是因为系统基于性能考虑,在每一行中存放着一个“未用区域”,来确保图片每行的byte数是4的倍数,那么如何去读某一行的字节数呢?

C#里面有一个Stride属性就可以用来获取,很简单吧。

static void Main(string[] args)
    {
      Bitmap bitmap = new Bitmap(Environment.CurrentDirectory + "//1.jpg");
 
      //定义锁定bitmap的rect的指定范围区域
      Rectangle rect = new Rectangle(0, 0, bitmap.Width, bitmap.Height);
 
      //加锁区域像素
      var bitmapData = bitmap.LockBits(rect, ImageLockMode.ReadWrite, bitmap.PixelFormat);
 
      //位图的首地址
      var ptr = bitmapData.Scan0;
 
      //stride:扫描行
      int len = bitmapData.Stride * bitmap.Height;
 
      var bytes = new byte[len];
 
      //锁定区域的像素值copy到byte数组中
      Marshal.Copy(ptr, bytes, 0, len);
 
      for (int i = 0; i < bitmap.Height; i++)
      {
        for (int j = 0; j < bitmap.Width * 3; j = j + 3)
        {
          var color = bytes[i * bitmapData.Stride + j + 2] * 0.299
                + bytes[i * bitmapData.Stride + j + 1] * 0.597
                + bytes[i * bitmapData.Stride + j] * 0.114;
 
          bytes[i * bitmapData.Stride + j]
               = bytes[i * bitmapData.Stride + j + 1]
               = bytes[i * bitmapData.Stride + j + 2] = (byte)color;
        }
      }
 
      //copy回位图
      Marshal.Copy(bytes, 0, ptr, len);
 
      //解锁
      bitmap.UnlockBits(bitmapData);
 
      bitmap.Save(Environment.CurrentDirectory + "//3.jpg");
    }


    
 
 
 
本站(WWW.)旨在分享和传播互联网科技相关的资讯和技术,将尽最大努力为读者提供更好的信息聚合和浏览方式。
本站(WWW.)站内文章除注明原创外,均为转载、整理或搜集自网络。欢迎任何形式的转载,转载请注明出处。












  • 相关文章推荐
  • Python中实现json字符串和dict类型的互转
  • 求意见如何在linux的应用软件中实现一个cpu调度框架,使得多个cpu调度算法可以在同一个系统中实现无缝整合?(分数不够还能再加)
  • 有没有在jsp中实现对tree型结构进行删除、插入操作
  • 如何在JAVA中实现类似VC中sprintf的功能
  • 在applet中实现文字超连接
  • 怎样在页面中实现表格功能
  • [求救]如何在telnet程序中实现下载功能。
  • 在c和c++中实现函数回调
  • 如何在JEditPanel中实现语法加亮,或者有什么其他的办法,哪里有这方面的教材?
  • 急急急,小问题,怎么在html的meta中实现转向功能,把它指引到另一页面上!??
  • 在JSP中实现文件上传的问题。
  • 如何在JSP页面中实现下载统计
  • JFrame怎样在WINDOWS中实现自动最大化?
  • 如何在java 的class中实现转向另一页?
  • 简单问题,怎么在Taglib中实现重定向。
  • 请教高手如何在jsp中实现图表功能?
  • 请问,类似于股市曲线那种,跟数据相关的曲线,怎么在JSP中实现?
  • 我需要在程序中实现将一个文件复制到其他结点的功能
  • 在web页面中实现树型结构
  • 如何在局域网中实现邮件系统
  • 如何在JB7中实现EJB helloworld! 配置和操作在线等!急!


  • 站内导航:


    特别声明:169IT网站部分信息来自互联网,如果侵犯您的权利,请及时告知,本站将立即删除!

    ©2012-2021,,E-mail:www_#163.com(请将#改为@)

    浙ICP备11055608号-3