ColorMatrix色彩矩阵的C#实践
哇啦哇啦部分
这个东西很多年前就出现了,虽然我近期才接触到…。既然用到了,就干脆把常用的矩阵记一记,总结一下吧。
ColorMatrix是一个4行5列的矩阵,有人叫它色彩矩阵,也有人叫它颜色矩阵,是一个很便利的东西。一张RGB模式存储的图片,其每一个像素点都有自己的RGB(RGBA)值。图像处理时,若想用一个固定算法遍历所有像素点,无疑矩阵的速度非常有优势。毕竟RGBA也可以看做一个向量。
在C#中,色彩矩阵是5行5列的矩阵,多了一行常数便于计算,颜色向量为[R,G,B,A,W]。W在计算结束后会被舍弃。由于颜色向量中每个元素的取值范围均为[0, 255],因此与它相乘的色彩矩阵的每一个元素则为255的倍数。例如色彩矩阵元素取值范围[-1, 1],对应计算结果范围[-255, 255],结果可以超出[0, 255],超出范围的值会被纠正为0或255。
例如色彩矩阵:
┌ a b c d e ┐
│ f g h i j │
│ k l m n o │
│ p q r s t │
└ u v w x y ┘
与颜色向量:
┌ R ┐
│ G │
│ B │
│ A │
└ W ┘
相乘,可获得新的颜色向量:
┌ R*a + G*f + B*k + A*p + W*u ┐
│ R*b + G*g + B*l + A*q + W*v │
│ R*c + G*h + B*m + A*r + W*w │
│ R*d + G*i + B*n + A*s + W*x │
└ R*e + G*j + B*o + A*t + W*y ┘
当初学线性代数的时候不好好学,觉得就能解个方程组。现在才发觉这玩意儿真好用,真香真香。
以上述为例,a,g,m取值-1,s,y,u,v,w取1,其他元素取0,那么结果为[ 255-R, 255-G, 255-B ],成功将颜色[ R, G, B ]反相。这就是W存在的便利之处。
实践部分
在C#中用色彩矩阵计算,要比依次取图片每一个像素进行计算要快很多。C#中无法将double型隐式转换为float型,所以色彩矩阵中出现小数时,要在后面加一个”f”。
全部代码如下:
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Windows.Forms;
namespace MatrixofColor
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
using (OpenFileDialog openFileDlg = new OpenFileDialog() { Filter = "Images|*.jpg" })
{
if (openFileDlg.ShowDialog() == DialogResult.OK)
{
picOriginal.Image = Image.FromFile(openFileDlg.FileName);
}
}
}
private void button2_Click(object sender, EventArgs e)
{
picConvert.Image = TransColor((Bitmap)picOriginal.Image);
}
private Bitmap TransColor(Bitmap original)
{
Bitmap newBitmap = new Bitmap(original.Width, original.Height);//建立空白bitmap
Graphics g = Graphics.FromImage(newBitmap);
ColorMatrix CM0 = new ColorMatrix(
new float[][]
{
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,.5f,0 },
new float[]{0,0,0,0,1 }
});//建立色彩矩阵
ImageAttributes attributes = new ImageAttributes();
attributes.SetColorMatrix(CM0);
g.DrawImage(original, new Rectangle(0, 0, original.Width, original.Height), 0, 0, original.Width, original.Height, GraphicsUnit.Pixel, attributes);
g.Dispose();
return newBitmap;
}
}
}
C#
以上代码实现的功能为,点击按钮1选择一张图片打开并显示,点击按钮2,显示运算结果。以下是常见的几个色彩矩阵。
透明度
ColorMatrix CM0 = new ColorMatrix(
new float[][]
{
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,.5f,0 },
new float[]{0,0,0,0,1 }
});
C#
降低透明度
灰度
ColorMatrix CM1 = new ColorMatrix(
new float[][]
{
new float[]{.30f,.30f,.30f,0,0 },
new float[]{.59f,.59f,.59f,0,0 },
new float[]{.11f,.11f,.11f,0,0 },
new float[]{0,0,0,1,0 },
new float[]{0,0,0,0,1 }
});
C#
灰度图
反相
ColorMatrix CM2 = new ColorMatrix(
new float[][]
{
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[]{1,1,1,0,1 }
});
C#
图片反相
亮度
ColorMatrix CM3 = new ColorMatrix(
new float[][]
{
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[]{.3f,.3f,.3f,0,1 }
});
C#
调节亮度
单通道
ColorMatrix CM4 = new ColorMatrix(
new float[][]
{
new float[]{1,0,0,0,0 },
new float[]{0,0,0,0,0 },
new float[]{0,0,0,0,0 },
new float[]{0,0,0,1,0 },
new float[]{0,0,0,0,1 }
});
C#
R通道
饱和度
float cmt5 = .3f;//0-1降饱和度,大于1升饱和度
ColorMatrix CM5 = new ColorMatrix(
new float[][]
{
new float[]{.213f+.787f*cmt5,.213f*(1-cmt5),.213f*(1-cmt5),0,0 },
new float[]{.715f*(1-cmt5),.715f+.285f*cmt5,.715f*(1-cmt5),0,0 },
new float[]{.072f*(1-cmt5),.072f*(1-cmt5),.072f+.928f*cmt5,0,0 },
new float[]{0,0,0,1,0 },
new float[]{0,0,0,0,1 }
});
C#
降低饱和度
增加饱和度
对比度
float cmt6 = 3;//0-1降对比度,1-10升对比度
ColorMatrix CM6 = new ColorMatrix(
new float[][]
{
new float[]{cmt6,0,0,0,0 },
new float[]{0,cmt6,0,0,0 },
new float[]{0,0,cmt6,0,0 },
new float[]{0,0,0,1,0 },
new float[]{.5f*(1-cmt6),.5f*(1-cmt6),.5f*(1-cmt6),0,1 }
});
C#
降低对比度
增加对比度
升温滤镜
ColorMatrix CM7 = new ColorMatrix(
new float[][]
{
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[]{.1f,.05f,-.03f,0,1 }
});
C#
升温滤镜 – 橙
冷却滤镜
ColorMatrix CM8 = new ColorMatrix(
new float[][]
{
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[]{-.03f,.05f,.1f,0,1 }
});
C#
冷却滤镜 – 蓝
复古滤镜
ColorMatrix CM9 = new ColorMatrix(
new float[][]
{
new float[]{.393f,.349f,.272f,0,0 },
new float[]{.769f,.686f,.534f,0,0 },
new float[]{.189f,.168f,.131f,0,0 },
new float[]{0,0,0,1,0 },
new float[]{0,0,0,0,1 }
});
C#
老照片滤镜
除以上示例外,还可以通过修改参数,形成不同的照片滤镜,甚至引入其他变量或函数达到复杂的计算目的