您当前位置: 圣才学习网首页 >> IT类 >> .NET程序设计

GDI+高频问题思考(10)

扫码手机阅读
用圣才电子书APP或微信扫一扫,在手机上阅读本文,也可分享给你的朋友。
评论(0
   
来源:网络 作者:未知
 
  今天来讲讲上个星期遗留下来的东西:ColorMatrix
 
  9. Color Matrix
 
  图像的本质是什么?对不同的人来说这是不同的东西。在计算机的世界中,啥东西都是数据,图像也是一种数据。从自然界的光变成计算机的数据,需要通过采样和量化的处理。图像在计算机中,其实是一个二维数组,从数学上来说,这其实是一个矩阵。图像中的每一个点都是个四维向量,也就是(RGBA),RGBA色彩空间中,我们可以使用一个矩阵对每一个点(RGBA)作矩阵乘法运算,这样就可以对图像色彩进行变换。这种做法其实是从三维空间坐标系中的仿射变换类推过来的。具体关于仿射变换,可以参考 http://en.wikipedia.org/wiki/Affine_transformation对于仿射变换的介绍。
 
  色彩矩阵就是这个用来对色彩作仿射变换的矩阵。这是一个5*5的矩阵,如图
 
  其实和在空间中的仿射变换完全一样,可以实现缩放,旋转,平移等功能。我看到网上有个人写了一篇深入浅出的文章"GDI ColorMatrix的完全揭秘与代码实现" http://blog.csdn.net/maozefa/archive/2008/09/08/2896752.aspx 写得不错,只是没有理解到ColorMatrix应用的精髓。简单套用了一些什么颜色剪切,颜色旋转,颜色平移的概念,这些东西其实在三维空间中很好理解,但是在色彩空间中,就完全不是那么回事情了,什么叫做颜色旋转60度呢?这东西忽悠人很有用,只是看完了还是不知道怎么用,有兴趣的同学可以去看看。我下面举几个例子,说明ColorMatrix的具体应用。
 
  a.灰度化
 
  灰度化是指去除图像的彩色信息,讲所有的色调归为0,所有的饱和度也归为零。这个世界上有很多种不同的灰度化的算法,随便写个算法,弄篇paper搞个硕士毕业应该不成问题,比如说所有的颜色替换成R' G' B' RBG/3。有一种很通用的灰度化算法如下,这其实是NTSC的色彩权重。
 
  R'B'G' 0.299*R 0.587*G 0.114*B
 
  那如果我们要使用ColorMatrix可以用以下的矩阵:
 
  // ColorMatrix elements
 
  float[][] ptsArray =
 
  {
 
  new float[] {0.299f, 0.299f, 0.299f, 0, 0}
 
  new float[] {0.518f, 0.518f, 0.518f, 0, 0}
 
  new float[] {0.114f, 0.114f, 0.114f, 0, 0}
 
  new float[] {0, 0, 0, 1, 0}
 
  new float[] {0, 0, 0, 0, 1}
 
  }
 
  再引用一下博客园里的这篇文章 http://www.cnblogs.com/sunbingzibo/archive/2008/09/11/1289260.html,如果用他的算法,那么矩阵如下
 
  // ColorMatrix elements
 
  float[][] ptsArray =
 
  {
 
  new float[] {cr,  cr, cr, 0, 0}
 
  new float[] {cg, cg, cg, 0, 0}
 
  new float[] {cb, cb, cb, 0, 0}
 
  new float[] {0, 0, 0, 1, 0}
 
  new float[] {0, 0, 0, 0, 1}
 
  }
 
  b.调整色彩
 
  使用ColorMatrix调整色彩很简单,用m11对红色乘一个系数,用m51对红色加一个值,这样就可以简单地调整红色。其他BGA通道以此类推。例如下面这个矩阵可以把增加红色25.5 个像素(如果使用24bppArgb:
 
  // ColorMatrix elements
 
  float[][] ptsArray =
 
  {
 
  new float[] {1, 0, 0, 0, 0},
 
  new float[] {0, 1, 0, 0, 0},
 
  new float[] {0, 0, 1, 0, 0},
 
  new float[] {0, 0, 0, 1, 0},
 
  new float[] {0.1f, 0, 0, 0, 1}
 
  };
 
 
  c. 调整亮度,可以用以下矩阵,将每个通道增加25.5的亮度
 
  // ColorMatrix  elements
 
  float[][] ptsArray =
 
  {
 
  new float[] {1, 0, 0, 0, 0},
 
  new float[] {0, 1, 0, 0, 0},
 
  new float[] {0, 0, 1, 0, 0},
 
  new float[] {0, 0, 0, 1, 0},
 
  new float[] {0.1f, 0.1f, 0.1f, 0, 1}
 
  };
 
  
 
  d.调整对比度,可以使用以下矩阵,将每个通道升高10%的对比度
 
  // ColorMatrix  elements
 
  float[][] ptsArray =
 
  {
 
  new float[] {1.1f, 0, 0, 0, 0},
 
  new float[] {0, 1.1f, 0, 0, 0},
 
  new float[] {0, 0, 1.1f, 0, 0},
 
  new float[] {0, 0, 0, 1, 0},
 
  new float[] {0, 0, 0, 0, 1}
 
  };
 
 
  很不幸,这是错的。这个算法里面有个关键的问题是Overflow,如果我们直接使用这个矩阵,你会看到图像上会有溢出,导致你的图像惨不忍睹。我在网上查到有个很发指的做法可以解决这个问题,虽然发指,但是能解决!就是把最下面的项修正一点点,这样图像就不溢出了。看下面这个矩阵。
 
  // ColorMatrix elements
 
  float[][] ptsArray =
 
  {
 
  new float[] {1.5f, 0, 0, 0, 0},
 
  new float[] {0, 1.5f, 0, 0, 0},
 
  new float[] {0, 0, 1.5f, 0, 0},
 
  new float[] {0, 0, 0, 1, 0},
 
  new float[] {0.001f, 0.001f, 0.001f, 0, 1}
 
  };
 
 
  e.调整饱和度
 
  这个矩阵比较复杂,饱和度需要通过不同的色彩权值来修正。我这里只提供一个能用的矩阵,具体可以参考这篇 paper:http://www.graficaobscura.com/matrix/index.html
 
  float rwgt =  0.3086f;
 
  float gwgt = 0.6094f;
 
  float bwgt = 0.0820f;
 
  float s = 1.2f;
 
  float[][] ptsArray =
 
  {
 
  new float[] {(1f-s)*rwgt+s, (1f-s)*rwgt, (1f-s)*rwgt, 0, 0},
 
  new float[] {(1f-s)*gwgt, (1f-s)*gwgt +s, (1f-s)*gwgt, 0, 0},
 
  new float[] {(1f-s)*bwgt, (1f-s)*bwgt, (1f-s)*bwgt + s, 0, 0},
 
  new float[] {0, 0, 0, 1, 0},
 
  new float[] {0, 0, 0, 0, 1}
 
  };
 
 
  讲了那么多个矩阵,最后让我们来看看在GDI+里面ColorMatrix这个类到底怎么用:
 
  FileStream fs = new FileStream(image, FileMode.Open,  FileAccess.Read);
 
  Image img = Image.FromStream(fs, false, false);
 
  Bitmap bmp = new Bitmap(img);
 
  img.Dispose();
 
  fs.Close();
 
  Graphics g = this.CreateGraphics();
 
  float rwgt = 0.3086f;
 
  float gwgt = 0.6094f;
 
  float bwgt = 0.0820f;
 
  float s = 1.2f;
 
  float[][] ptsArray =
 
  {
 
  new float[] {(1f-s)*rwgt+s, (1f-s)*rwgt, (1f-s)*rwgt, 0, 0},
 
  new float[] {(1f-s)*gwgt, (1f-s)*gwgt +s, (1f-s)*gwgt, 0, 0},
 
  new float[] {(1f-s)*bwgt, (1f-s)*bwgt, (1f-s)*bwgt + s, 0, 0},
 
  new float[] {0, 0, 0, 1, 0},
 
  new float[] {0, 0, 0, 0, 1}
 
  };
 
  // Create a ColorMatrix
 
  ColorMatrix matrix = new ColorMatrix(ptsArray);
 
  ImageAttributes attr = new ImageAttributes();
 
  // Set color matrix
 
  attr.SetColorMatrix(matrix,
 
  ColorMatrixFlag.Default,
 
  ColorAdjustType.Default);
 
  // Draw image with no affects
 
  g.DrawImage(bmp, 0, 0, 200, 150);
 
  // Draw image with ImageAttributes
 
  g.DrawImage(bmp,
 
  new Rectangle(205, 0, 200, 150),
 
  0, 0, bmp.Width, bmp.Height,
 
  GraphicsUnit.Pixel, attr);
 
  // Dispose
 
  bmp.Dispose();
 
  g.Dispose();
 
  多少博士大牛在研究这些不同的矩阵以期获得更强悍的效果。此外还有好多人申请了各种各样的专利来保护这个色彩变换,所以如果大家想混一篇简单的paper好毕业,这是个很好的方向。随便改两个数字,一个新的矩阵就出来了,然后版面费一交,就可以发表了。当然,这也是个蛮有意思的题目,可以做很多比较和研究,这些就不是我这种IT民工该讲的东西了
 
  相关阅读
 
 

小编工资已与此挂钩!一一分钱!求打赏↓ ↓ ↓

如果你喜欢本文章,请赐赏:

已赐赏的人
最新评论(共0条)评论一句