17.3.4 颜色矩阵
版权声明:本文为博主原创文章,转载请在显著位置标明本文出处以及作者网名,未经作者允许不得用于商业目的。
17.3.4.1 矩阵基本概念
矩阵(Matrix)是一个按照长方阵列排列的复数或实数集合,类似于数组。
由于在图像处理时使用到矩阵的乘法,这里只谈谈矩阵的乘法运算。
矩阵乘法运算公式:

图17-56 矩阵乘法运算公式
在C#中,矩阵使用了颜色的四个分量:红色分量R、绿色分量G、蓝色分量B、透明度A。但光是依靠上述4个分量,不足以完全实现矩阵变换,所以再加上一个用来进行颜色增减的分量W,而W始终等于255。
假设变换前的5个颜色分量为R、G、B、A、W;
变换后的5个颜色分量为R’、G’、B’、A’、W’,
乘以一个5×5的矩阵,得到公式如下:

图17-57 颜色矩阵乘法公式
R’、G’、B’、A’、W’对应的值分别为:
R'= R*r1+G*g1+B*b1+A*a1+W*w1
G’= R*r2+G*g2+B*b2+A*a2+W*w2
B’= R*r3+G*g3+B*b3+A*a3+W*w3
A’= R*r4+G*g4+B*b4+A*a4+W*w4
W’= R*r5+G*g5+B*b5+A*a5+W*w5
在这个公式基础上,先来看几组比较常见的变换:
1、变换后颜色相同:

图17-58 矩阵变换:相同矩阵
具体计算过程:
R'= R*1+G*0+B*0+A*0+W*0 =R
G’= R*0+G*1+B*0+A*0+W*0 =G
B’= R*0+G*0+B*1+A*0+W*0 =B
A’= R*0+G*0+B*0+A*1+W*0 =A
W’= R*0+G*0+B*0+A*0+W*1 =W
2、仅保留红色分量:

图17-59 矩阵变换:保留红色分量
3、仅保留绿色分量:

图17-60 矩阵变换:保留绿色分量
4、仅保留蓝色分量:

图17-61 矩阵变换:保留蓝色分量
5、灰度变换:平均值法,参看第17.3.1.3节:

图17-62 矩阵变换:灰度平均值
R'= R*0.33+G*0.33+B*0.33+A*0+W*0
G’=R*0.33+G*0.33+B*0.33+A*0+W*0
B’= R*0.33+G*0.33+B*0.33+A*0+W*0
A’= A
W’= 0
6、灰度变换:指数加权法,参看第17.3.1.3节:

图17-63 矩阵变换:灰度指数加权
R'= R*0.30+G*0.59+B*0.11
G’=R*0.30+G*0.59+B*0.11
B’= R*0.30+G*0.59+B*0.11
A’= A
W’= 0
7、逆反,参看第17.3.1.1节:

图17-64 矩阵变换:逆反
R'= R*-1+G*0+B*0+A*0+W*0 =-R
G’=R*0+G*-1+B*0+A*0+W*0=-G
B’= R*0+G*0+B*-1+A*0+W*0 =-B
A’= R*0+G*0+B*0+A*1+W*0 =A
W’= R*0+G*0+B*0+A*0+W*0 = 0
在理想化的情况下,以红色分量为例:如果R=10,R逆反后为-R,即-10。由于R是Byte(范围是0-255),因此R=255-10=245。但是,实际情况下,C#可以那样运算,VB.Net不行,-10由于小于0,直接被转成了0;同样其它两个分量G、B,由于是负数,都直接成了0。使用上面逆反矩阵的话,得到的图像永远是一片白色的。
下面才是正确的逆反矩阵:

图17-65 矩阵变换:逆反修正
R'= R*-1+G*0+B*0+A*0+W*1 =255-R
G’=R*0+G*-1+B*0+A*0+W*1=255-G
B’= R*0+G*0+B*-1+A*0+W*1 =255-B
A’= R*0+G*0+B*0+A*1+W*0 =A
W’= R*0+G*0+B*0+A*0+W*0 = 0
下一节我们将实战使用以上的矩阵公式。
17.3.4.2 ColorMatrix类
ColorMatrix(颜色矩阵)类是一个包含 RGBAW 空间坐标的 5 x 5 矩阵。ImageAttributes类的SetColorMatrix和SetColorMatrices方法通过使用ColorMatrix调整图像颜色。
ColorMatrix常用属性:
Item:ColorMatrix中位于指定的行和列的元素。
Matrix00:Single,单精度浮点数。 ColorMatrix 第 0行第 0 列的元素 (注意,同数组,矩阵行列的起始从0开始)。
Matrix01:Single,单精度浮点数。ColorMatrix 第 0行第 1 列的元素。
……
Matrix44:Single,单精度浮点数。ColorMatrix 第 4行第4 列的元素。
Matrix00-Matrix44的位置如下图:

图17-66 ColorMatrix元素位置
ColorMatrix的构造函数包括两个版本的重载:
1、public ColorMatrix()
2、public ColorMatrix( float[][] newColorMatrix )
第一种方法是声明一个ColorMatrix实例,然后使对它的属性Matrix00-Matrix44赋值。
常用的是第二种,定义并初始化一个二位数组,然后用构造函数 ColorMatrix(Single()()) 直接初始化一个Matrix,例如以下代码:
float[][] imgMatrixElement= {
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, 0}
}
Dim imgMatrix As New ColorMatrix(imgMatrixElement)
当实例化一个ColorMatrix后并给它的各个元素赋值后,就可以使用imageAttributes的SetColorMatrix方法,为图像设置颜色矩阵,例如:
imageAttributes.SetColorMatrix(imgMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);
上述代码使用的是SetColorMatrix方法的以下重载版本:
public void SetColorMatrix( ColorMatrix newColorMatrix, ColorMatrixFlag mode, ColorAdjustType type )
参数说明:
- newColorMatrix:要进行颜色调整的矩阵。
- grayMatrix:这是一个ColorMatrixFlag 枚举,包含以下成员:
- AltGrays:仅调整灰色底纹。
- Default:指定所有的颜色值(包括灰色底纹)都由同样的颜色调整矩阵来调整。
- SkipGrays:指定调整所有颜色,但不调整灰色底纹。 灰色底纹是指其红色、绿色和蓝色分量的值都相同的任何颜色。
通常情况下使用的是 ColorMatrixFlag.Default。
- 参数flags:这是一个ColorAdjustType枚举,包含以下成员:
- Any:指定的类型的数目。
- Bitmap:Bitmap 对象的颜色调整信息。
- Brush:Brush 对象的颜色调整信息。
- Count:指定的类型的数目。
- Default:自身没有颜色调整信息的所有 GDI+ 对象所使用的颜色调整信息。
- Pen:Pen 对象的颜色调整信息。
- Text:文本的颜色调整信息。
通常情况对图像的颜色进行调整,使用ColorAdjustType.Bitmap。
【例 17.57】【项目:code17-035】使用矩阵灰度化图像。
本例中使用了第17.3.4.1节中灰度变换平均值法的矩阵。
窗体级变量、窗体载入、载入图片的代码请参看第17.3.1节【项目:code17-031】。
主要代码如下:
private void btnGray_Click(object sender, EventArgs e)
{
ImageAttributes imageAttributes = new ImageAttributes();
DateTime timeStart, timeEnd;
TimeSpan timeDiff;
timeStart = DateTime.Now;
//灰度平均值法
float [][] imgMatrixElement = {
new float [] { 0.33f, 0.33f, 0.33f, 0, 0},
new float [] { 0.33f, 0.33f, 0.33f, 0, 0},
new float [] { 0.33f, 0.33f, 0.33f, 0, 0},
new float [] { 0, 0, 0, 1, 0},
new float [] { 0, 0, 0, 0, 0}
};
ColorMatrix imgMatrix = new ColorMatrix(imgMatrixElement);
imageAttributes.SetColorMatrix(imgMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);
Bitmap destImg = new Bitmap(sourceImg.Width, sourceImg.Height);
Graphics g = Graphics.FromImage(destImg);
g.DrawImage(sourceImg, new Rectangle(0, 0, sourceImg.Width, sourceImg.Height), 0, 0, sourceImg.Width, sourceImg.Height,
GraphicsUnit.Pixel, imageAttributes);
picDest.Image = destImg;
timeEnd = DateTime.Now;
timeDiff = timeEnd - timeStart;
lblByMatrix.Text = timeDiff.TotalMilliseconds + "ms";
}
运行结果如下图所示:

图17-67 使用矩阵灰度化图像
从图17-57可以看到,使用矩阵处理图像所耗费的时间约为340.12ms,处理速度间于像素处理与内存处理,使用矩阵的代码比使用内存的代码更简洁,但是像素处理和内存处理更为灵活,应该根据实际需要选择图像处理方式。
【例 17.58】【项目:code17-036】矩阵综合运用。
窗体上放置25个TextBox,名称从“txt00”到“txt44”,分别对应矩阵属性Matrix00至Matrix44。放置1个ComboBox,用于设置常见的矩阵值。
主要代码如下:
Bitmap sourceImg;
private void Form1_Load(object sender, EventArgs e)
{
picSource.SizeMode = PictureBoxSizeMode.StretchImage;
picDest.SizeMode = PictureBoxSizeMode.StretchImage;
cbMatrixType.DropDownStyle = ComboBoxStyle.DropDownList;
cbMatrixType.Items.Add("全部重置");
cbMatrixType.Items.Add("保留红色分量");
cbMatrixType.Items.Add("保留绿色分量");
cbMatrixType.Items.Add("保留蓝色分量");
cbMatrixType.Items.Add("灰度平均值");
cbMatrixType.Items.Add("灰度指数加权");
cbMatrixType.Items.Add("逆反");
cbMatrixType.Text = cbMatrixType.Items[0].ToString();
}
private void btnLoad_Click(object sender, EventArgs e)
{
OpenFileDialog ofd = new OpenFileDialog();
ofd.Filter = "图片文件|*.jpg;*.png";
if (ofd.ShowDialog() != DialogResult.OK)
return;
sourceImg = (Bitmap)Image.FromFile(ofd.FileName);
picSource.Image = sourceImg;
}
private void btnDraw_Click(object sender, EventArgs e)
{
ImageAttributes imageAttributes =new ImageAttributes();
ColorMatrix imgMatrix =new ColorMatrix();
TextBox txtControl;
for (int i = 0; i < 5; i++)
{
for (int j = 0; j < 5; j++)
{
txtControl = (TextBox)(this.Controls["txt" + i + j]);
//矩阵相当于是二维数组
imgMatrix[i, j] = Single.Parse(txtControl.Text);
}
}
imageAttributes.SetColorMatrix(imgMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);
Bitmap destImg =new Bitmap(sourceImg.Width, sourceImg.Height);
Graphics g = Graphics.FromImage(destImg);
g.DrawImage(sourceImg, new Rectangle(0, 0, sourceImg.Width, sourceImg.Height), 0, 0, sourceImg.Width, sourceImg.Height,
GraphicsUnit.Pixel, imageAttributes);
picDest.Image = destImg;
}
private void cbMatrixType_SelectedIndexChanged(object sender, EventArgs e)
{
setMatrixType();
}
private void setMatrixType()
{
//重置矩阵的值
resetText();
switch(cbMatrixType.Text)
{
case "全部重置":
//不处理
break;
case "保留红色分量":
txt00.Text = "1";
txt33.Text = "1";
break;
case "保留绿色分量":
txt11.Text = "1";
txt33.Text = "1";
break;
case "保留蓝色分量":
txt22.Text = "1";
txt33.Text = "1";
break;
case "灰度平均值":
txt00.Text = "0.33";
txt01.Text = "0.33";
txt02.Text = "0.33";
txt10.Text = "0.33";
txt11.Text = "0.33";
txt12.Text = "0.33";
txt20.Text = "0.33";
txt21.Text = "0.33";
txt22.Text = "0.33";
txt33.Text = "1";
break;
case "灰度指数加权":
txt00.Text = "0.30";
txt01.Text = "0.30";
txt02.Text = "0.30";
txt10.Text = "0.59";
txt11.Text = "0.59";
txt12.Text = "0.59";
txt20.Text = "0.11";
txt21.Text = "0.11";
txt22.Text = "0.11";
txt33.Text = "1";
break;
case "逆反":
txt00.Text = "-1";
txt11.Text = "-1";
txt22.Text = "-1";
txt40.Text = "1";
txt41.Text = "1";
txt42.Text = "1";
txt33.Text = "1";
break;
default:
break;
}
}
//将矩阵关联的文本框全部重置为0
private void resetText()
{
TextBox txtControl;
for( int i = 0;i<5;i++)
{
for(int j = 0;j< 5;j++)
{
//强制类型转换为相应名称的控件
txtControl = (TextBox)(this.Controls["txt" + i + j]);
txtControl.Text = "0";
}
}
}
运行结果如下图所示:

图17-68 使用矩阵处理图像
学习更多vb.net知识,请参看vb.net 教程 目录
学习更多C#知识,请参看C#教程 目录
相关文章:
17.3.4 颜色矩阵
版权声明:本文为博主原创文章,转载请在显著位置标明本文出处以及作者网名,未经作者允许不得用于商业目的。 17.3.4.1 矩阵基本概念 矩阵(Matrix)是一个按照长方阵列排列的复数或实数集合,类似于数组。 由…...
【C++】多态详细讲解
本篇来聊聊C面向对象的第三大特性-多态。 1.多态的概念 多态通俗来说就是多种形态。多态分为编译时多态(静态多态)和运⾏时多态(动态多态)。 编译时多态:主要就是我们前⾯讲的函数重载和函数模板,他们传不同类型的参数就可以调⽤不同的函数,通…...
4. k8s二进制集群之ETCD集群证书生成
安装cfssl工具配置CA证书请求文件创建CA证书创建CA证书策略配置etcd证书请求文件生成etcd证书 继续上一篇文章《负载均衡器高可用部署》下面介绍一下etcd证书生成配置。其中涉及到的ip地址和证书基本信息请替换成你自己的信息。 安装cfssl工具 下载cfssl安装包 https://github…...
Drools规则引擎初体验
前言 假设有这样一个场景,订单管理系统需要根据用户的消费情况,来为每个用户发放不同程度的优惠券,这个发放规则复杂且多变,我们该怎么办?在代码中写死显然是不可取的,规则一变就要修改代码,频…...
Day36【AI思考】-表达式知识体系总览
文章目录 **表达式知识体系总览**回答1:**表达式知识体系****一、三种表达式形式对比****二、表达式转换核心方法****1. 中缀转后缀(重点)****2. 中缀转前缀** **三、表达式计算方法****1. 后缀表达式计算(栈实现)****…...
Tailwind CSS v4.0 升级与 Astro 5.2 项目迁移记录
本文博客链接 https://ysx.cosine.ren/tailwind-update-v4-migrate 自用小记。 Tailwind CSS v4.0 - Tailwind CSS 新的高性能引擎 - 完整构建的速度速度快 5 倍,增量构建的速度快于 100 倍以上 —— 以微秒为单位进行测量。为现代 Web 设计 - 建立在前沿的 CSS 特…...
K8S ReplicaSet 控制器
一、理论介绍 今天我们来实验 ReplicaSet 控制器(也叫工作负载)。官网描述如下: 1、是什么? ReplicaSet 副本集, 维护一组稳定的副本 Pod 集合。 2、为什么需要? 解决 pod 被删除了,不能自我恢…...
基于springboot校园点歌系统
基于Spring Boot的校园点歌系统是一种专为校园场景设计的音乐点播平台,它能够丰富学生的校园生活,提升学生的娱乐体验。以下是对该系统的详细介绍: 一、系统背景与意义 在校园环境中,学生们对于音乐有着浓厚的兴趣,传…...
【R语言】数据操作
一、查看和编辑数据 1、查看数据 直接打印到控制台 x <- data.frame(a1:20, b21:30) x View()函数 此函数可以将数据以电子表格的形式进行展示。 用reshape2包中的tips进行举例: library("reshape2") View(tips) head()函数 查看前几行数据&…...
【C++】2.高并发内存池 -- 如何设计一个定长内存池
博客主题:如何设计一个定长内存池 个人主页:https://blog.csdn.net/sobercq CSDN专栏:https://blog.csdn.net/sobercq/category_12884309.html Gitee链接:https://gitee.com/yunshan-ruo/high-concurrency-memory-pool 文章目录 前…...
Redis --- 使用Feed流实现社交平台的新闻流
要实现一个 Feed 流(类似于社交媒体中的新闻流),通常涉及以下几个要素: 内容发布:用户发布内容(例如文章、状态更新、图片等)。内容订阅:用户可以订阅其他用户的内容,获…...
React中key值的正确使用指南:为什么需要它以及如何选择
React中key值的正确使用指南:为什么需要它以及如何选择 一、key值的基本概念二、如何选择合适的key值1. 数据来源决定key策略2. key值的三大核心要求 三、React为何需要key值?1. 虚拟DOM优化机制2. 状态维护机制 四、常见误区及解决方案1. 索引作为key的…...
在Debian 12上安装VNC服务器
不知道什么标题 可以看到这个文章是通过豆包从国外网站copy的,先这样写着好了,具体的我有时间再补充,基本内容都在这里了。 在Debian 12上安装VNC服务器 简介 VNC(Virtual Network Computing,虚拟网络计算…...
游戏引擎学习第88天
仓库:https://gitee.com/mrxiao_com/2d_game_2 调查碰撞检测器中的可能错误 在今天的目标是解决一个可能存在的碰撞检测器中的错误。之前有人提到在检测器中可能有一个拼写错误,具体来说是在测试某个变量时,由于引入了一个新的变量而没有正确地使用它&…...
c++中priority_queue的应用及模拟实现
1.介绍 priority_queue 是一种数据结构,它允许你以特定的顺序存储和访问元素。在 C 标准模板库(STL)中,priority_queue 是一个基于容器适配器的类模板,它默认使用 std::vector 作为底层容器,并且默认使用最…...
深度学习篇---计算机视觉任务模型的剪裁、量化、蒸馏
文章目录 前言第一部分:计算机视觉任务图像分类特点 图像识别特点 目标检测特点 图像分割子任务特点 第二部分:模型剪裁、量化、蒸馏模型剪裁1.权重剪裁2.结构剪裁3.迭代剪裁 模型量化1.对称量化2.非对称量化3.动态量化4.静态量化 知识蒸馏1.训练教师网络…...
java-关键字(final,static)
关键字 final 和 static 是两个常用的关键字,它们分别用于不同的场景,具有不同的作用。 final final 关键字用于表示某个实体是不可变的。它可以应用于变量、方法和类。 final 变量 当 final 用于变量时,表示该变量一旦被初始化后&#…...
游戏引擎 Unity - Unity 设置为简体中文、Unity 创建项目
Unity Unity 首次发布于 2005 年,属于 Unity Technologies Unity 使用的开发技术有:C# Unity 的适用平台:PC、主机、移动设备、VR / AR、Web 等 Unity 的适用领域:开发中等画质中小型项目 Unity 适合初学者或需要快速上手的开…...
JDK17主要特性
JDK 17,也被称为Java 17或Java Platform, Standard Edition 17,是Java编程语言的第十七个主要版本,由Oracle公司在2021年9月发布。Java 17是一个长期支持(LTS,Long-Term Support)版本,这意味着它…...
将OneDrive上的文件定期备份到移动硬盘
背景: 我在oneDrive上存了很多文件,分布在多个文件夹中,也有套了好几层文件夹的情况。我希望每隔一段时间,将oneDrive上的所有文件向移动硬盘上拷贝一份,但是我只想将距离上一次向移动硬盘拷贝的文件相比,发…...
【Elasticsearch】geohex grid聚合
在 Elasticsearch 中,地理边界过滤是一种用于筛选地理数据的技术,它可以根据指定的地理边界形状(如矩形、多边形等)来过滤符合条件的文档。这种方法在地理空间数据分析中非常有用,尤其是在需要将数据限制在特定地理区域…...
crewai框架第三方API使用官方RAG工具(pdf,csv,json)
最近在研究调用官方的工具,但官方文档的说明是在是太少了,后来在一个视频里看到了如何配置,记录一下 以PDF RAG Search工具举例,官方文档对于自定义模型的说明如下: 默认情况下,该工具使用 OpenAI 进行嵌…...
算法 哈夫曼树和哈夫曼编码
目录 前言 一,二进制转码 二,哈夫曼编码和哈夫曼树 三,蓝桥杯 16 哈夫曼树 总结 前言 这个文章需要有一定的树的基础,没学过树的伙伴可以去看我博客树的文章 当我们要编码一个字符串转成二进制的时候,我们要怎么…...
TCP 丢包恢复策略:代价权衡与优化迷局
网络物理层丢包是一种需要偿还的债务,可以容忍低劣的传输质量,这为 UDP 类服务提供了空间,而对于 TCP 类服务,可以用另外两类代价来支付: 主机端采用轻率的 GBN 策略恢复丢包,节省 CPU 资源,但…...
Sumatra PDF:小巧免费,满足多样阅读需求
Sumatra PDF是一款完全免费的本地阅读器软件,以小巧的体积和全面的功能受到用户青睐。如今,它已经更新到3.3版本,带来了更多实用功能,尤其是新增的注释功能,值得我们再次关注。 软件特色 轻量级体积:压缩…...
vue2-给data动态添加属性
vue2-给data动态添加属性 1. 问题的来源 在VUe2中(VUE3中使用了proxy,及时动态添加也能实现响应式),如果我们动态给data添加一个属性,会发现视图没有同步更新举个例子我们通过v-for遍历data中的一个属性list…...
TiDB 分布式数据库多业务资源隔离应用实践
导读 随着 TiDB 在各行业客户中的广泛应用 ,特别是在多个业务融合到一套 TiDB 集群中的场景,各企业对集群内多业务隔离的需求日益增加。与此同时,TiDB 在多业务融合场景下的资源隔离方案日趋完善,详情可参考文章 《你需要什么样的…...
105,【5】buuctf web [BJDCTF2020]Easy MD5
进入靶场 先输入试试回显 输入的值成了password的内容 查看源码,尝试得到信息 什么也没得到 抓包,看看请求与响应里有什么信息 响应里得到信息 hint: select * from admin where passwordmd5($pass,true) 此时需要绕过MD5()函…...
BFS(广度优先搜索)——搜索算法
BFS,也就是广度(宽度)优先搜索,二叉树的层序遍历就是一个BFS的过程。而前、中、后序遍历则是DFS(深度优先搜索)。从字面意思也很好理解,DFS就是一条路走到黑,BFS则是一层一层地展开。…...
33.Word:国家中长期人才发展规划纲要【33】
目录 NO1.2样式 NO3 图表 NO4.5.6 开始→段落标记视图→导航窗格→检查有无遗漏 NO1.2样式 F12/另存为:Word.docx:考生文件夹样式的复制样式的修改 样式的应用(没有相似/超级多的情况下)——替换 [ ]通配符&#x…...
