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 )

参数说明:

  1. newColorMatrix:要进行颜色调整的矩阵。
  2. grayMatrix:这是一个ColorMatrixFlag 枚举,包含以下成员:
  1. AltGrays:仅调整灰色底纹。
  2. Default:指定所有的颜色值(包括灰色底纹)都由同样的颜色调整矩阵来调整。
  3. SkipGrays:指定调整所有颜色,但不调整灰色底纹。 灰色底纹是指其红色、绿色和蓝色分量的值都相同的任何颜色。

    通常情况下使用的是 ColorMatrixFlag.Default。

  1. 参数flags:这是一个ColorAdjustType枚举,包含以下成员:
  1. Any:指定的类型的数目。
  2. Bitmap:Bitmap 对象的颜色调整信息。
  3. Brush:Brush 对象的颜色调整信息。
  4. Count:指定的类型的数目。
  5. Default:自身没有颜色调整信息的所有 GDI+ 对象所使用的颜色调整信息。
  6. Pen:Pen 对象的颜色调整信息。
  7. 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#教程 目录

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/963275.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

LabVIEW在电机自动化生产线中的实时数据采集与生产过程监控

在电机自动化生产线中&#xff0c;实时数据采集与生产过程监控是确保生产效率和产品质量的重要环节。LabVIEW作为一种强大的图形化编程平台&#xff0c;可以有效实现数据采集、实时监控和自动化控制。详细探讨如何利用LabVIEW实现这一目标&#xff0c;包括硬件选择、软件架构设…

mybatis(78/134)

前天学了很多&#xff0c;关于java的反射机制&#xff0c;其实跳过了new对象&#xff0c;然后底层生成了字节码&#xff0c;创建了对应的编码。手搓了一遍源码&#xff0c;还是比较复杂的。 <?xml version"1.0" encoding"UTF-8" ?> <!DOCTYPE …

【NLP251】Transformer精讲 残差链接与层归一化

精讲部分&#xff0c;主要是对Transformer的深度理解方便日后从底层逻辑进行创新&#xff0c;对于仅应用需求的小伙伴可以跳过这一部分&#xff0c;不影响正常学习。 1. 残差模块 何凯明在2015年提出的残差网络&#xff08;ResNet&#xff09;&#xff0c;Transformer在2016年…

全程Kali linux---CTFshow misc入门(25-37)

第二十五题&#xff1a; 提示&#xff1a;flag在图片下面。 直接检查CRC&#xff0c;检测到错误&#xff0c;就直接暴力破解。 暴力破解CRC的python代码。 import binascii import struct def brute_force_ihdr_crc(filename): # 读取文件二进制数据 with open(filen…

OpenAI深夜反击:o3-mini免费上线,能否撼动DeepSeek的地位?

还在为寻找合适的 AI 模型而烦恼吗&#xff1f;chatTools 平台为您精选 o1、GPT4o、Claude、Gemini 等顶尖 AI 模型&#xff0c;满足您不同的 AI 应用需求。立即体验强大的 AI 能力&#xff01; 深夜反击&#xff0c;OpenAI祭出o3-mini 在DeepSeek异军突起&#xff0c;搅动AI行…

蓝桥杯备考:模拟算法之字符串展开

P1098 [NOIP 2007 提高组] 字符串的展开 - 洛谷 | 计算机科学教育新生态 #include <iostream> #include <cctype> #include <algorithm> using namespace std; int p1,p2,p3; string s,ret; void add(char left,char right) {string tmp;for(char ch left1;…

NLP深度学习 DAY5:Sequence-to-sequence 模型详解

Seq2Seq&#xff08;Sequence-to-Sequence&#xff09;模型是一种用于处理输入和输出均为序列任务的深度学习模型。它最初被设计用于机器翻译&#xff0c;但后来广泛应用于其他任务&#xff0c;如文本摘要、对话系统、语音识别、问答系统等。 核心思想 Seq2Seq 模型的目标是将…

于动态规划的启幕之章,借 C++ 笔触绘就算法新篇

注意&#xff1a;代码由易到难 P1216 [IOI 1994] 数字三角形 Number Triangles 题目链接&#xff1a;[IOI 1994] 数字三角形 Number Triangles - 洛谷 题目描述 观察下面的数字金字塔。 写一个程序来查找从最高点到底部任意处结束的路径&#xff0c;使路径经过数字的和最大。每…

Three.js 后期处理(Post-Processing)详解

目录 前言 一、什么是后期处理&#xff1f; 二、Three.js 后期处理的工作流程 2.1 创建 EffectComposer 2.2 添加渲染通道&#xff08;Render Pass&#xff09; 2.3 应用最终渲染 三、后期处理实现示例 3.1 基础代码 四、常见的后期处理效果 4.1 辉光效果&#xf…

低代码系统-产品架构案例介绍、炎黄盈动-易鲸云(十二)

易鲸云作为炎黄盈动新推出的产品&#xff0c;在定位上为低零代码产品。 开发层 表单引擎 表单设计器&#xff0c;包括设计和渲染 流程引擎 流程设计&#xff0c;包括设计和渲染&#xff0c;需要说明的是&#xff1a;采用国际标准BPMN2.0&#xff0c;可以全球通用 视图引擎 视图…

从 HTTP/1.1 到 HTTP/3:如何影响网页加载速度与性能

一、前言 在最近使用Apipost时&#xff0c;突然注意到了http/1.1和http/2&#xff0c;如下图&#xff1a; 在我根深蒂固的记忆中&#xff0c;对于http的理解还停留在TCP协议、三次握手。由于我的好奇心&#xff0c;于是触发了我被动“开卷”&#xff0c;所以有了这篇文章&…

项目练习:重写若依后端报错cannot be cast to com.xxx.model.LoginUser

文章目录 一、情景说明二、解决办法 一、情景说明 在重写若依后端服务的过程中 使用了Redis存放LoginUser对象数据 那么&#xff0c;有存就有取 在取值的时候&#xff0c;报错 二、解决办法 方法1、在TokenService中修改如下 getLoginUser 方法中&#xff1a;LoginUser u…

C语言------二维数组指针从入门到精通

前言: 目标:需要了解及掌握数组指针的行地址、列地址、具体元素地址、具体元素地址的值是怎样定义及实现。 重点:指针的偏移,指针解引用。 难点:指针的升阶与降阶。 1. 基本概念 二维数组&#xff1a;二维数组可以看作是一个数组的数组。例如&#xff0c;int a[3][4] 表示一个 …

AI-ISP论文Learning to See in the Dark解读

论文地址&#xff1a;Learning to See in the Dark 图1. 利用卷积网络进行极微光成像。黑暗的室内环境。相机处的照度小于0.1勒克斯。索尼α7S II传感器曝光时间为1/30秒。(a) 相机在ISO 8000下拍摄的图像。(b) 相机在ISO 409600下拍摄的图像。该图像存在噪点和色彩偏差。©…

自定义数据集 ,使用朴素贝叶斯对其进行分类

代码&#xff1a; # 导入必要的库 import numpy as np import matplotlib.pyplot as plt# 定义类1的数据点&#xff0c;每个数据点是二维的坐标 class1_points np.array([[1.9, 1.2],[1.5, 2.1],[1.9, 0.5],[1.5, 0.9],[0.9, 1.2],[1.1, 1.7],[1.4, 1.1]])# 定义类2的数据点&…

蓝桥杯单片机第七届省赛

前言 这套题不难&#xff0c;相对于第六套题这一套比较简单了&#xff0c;但是还是有些小细节要抓 题目 OK&#xff0c;以上就是全部的题目了&#xff0c;这套题目相对来说逻辑比较简单&#xff0c;四个按键&#xff0c;S4控制pwm占空比&#xff0c;S5控制计时时间&#xff0…

小程序设计和开发:如何研究同类型小程序的优点和不足。

一、确定研究目标和范围 明确研究目的 在开始研究同类型小程序之前&#xff0c;首先需要明确研究的目的。是为了改进自己的小程序设计和开发&#xff0c;还是为了了解市场趋势和用户需求&#xff1f;不同的研究目的会影响研究的方法和重点。例如&#xff0c;如果研究目的是为了…

反向代理模块jmh

1 概念 1.1 反向代理概念 反向代理是指以代理服务器来接收客户端的请求&#xff0c;然后将请求转发给内部网络上的服务器&#xff0c;将从服务器上得到的结果返回给客户端&#xff0c;此时代理服务器对外表现为一个反向代理服务器。 对于客户端来说&#xff0c;反向代理就相当…

一文讲解HashMap线程安全相关问题

HashMap不是线程安全的&#xff0c;主要有以下几个问题&#xff1a; ①、多线程下扩容会死循环。JDK1.7 中的 HashMap 使用的是头插法插入元素&#xff0c;在多线程的环境下&#xff0c;扩容的时候就有可能导致出现环形链表&#xff0c;造成死循环。 JDK 8 时已经修复了这个问…

oracle:子查询

子查询: 一条查询语句中嵌入了另一条查询语句, 被嵌入里面的这条查询语句称为子查询, 外面的查询语句称为主查询 子查询的分类 相关性子查询&#xff08;Correlated Subquery&#xff09;是指子查询的执行依赖于外部查询的每一行数据。也就是说&#xff0c;子查询会对外部查询…