此次工程文件是编写一个可进行矩阵基本操作与应用的项目。这个项目主要由8大作用,这些作用将在项目的目录中逐一展示,供使用者查看并选取自己想进行的操作。这8大作用分别为:
- 矩阵加法;
- 矩阵数乘;
- 矩阵转置;
- 矩阵乘法;
- Hadamard乘积;
- 矩阵卷积;
- 卷积应用;
- OTSU算法。
另外包含有退出系统的人性化操作,即0、退出系统,因此目录中将显示九个选项。
在每个功能中,使用者只需按照系统的引导,输入相应的数据即可。
在设计程序时,将主函数置于最后,并构造若干函数用于实现各个矩阵运算。另外,设计程序时要考虑到人性化,因此,在程序开始时,设置一个列表(目录),供使用者选择,并按照程序一步一步的指示进行。
- 我认为在开始所有项目之前,都要对最基本的框架进行调试,而后再进行内部的细化。因此首先是目录的挑选和清屏问题:这需要自己考虑所有输入及错误形式,并查看程序是否能应对所有可能情况。这一点自己摸索即可,并无太难问题。
- 进行矩阵加法数乘都无问题,矩阵乘法如果没有思路,可写出矩阵相乘的公式$ c_{ij}=\sum_{k=1}^{s}a_{ik}*b_{kj} $。可以看出,在i与j两重循坏之下,可以再加上对于k的一重循坏。如此构成的三重循坏就可以实现矩阵相乘。
- 进行矩阵卷积时,需要进行复杂的思考且容易出错。可以依照前面的hadamard运算,再考虑将矩阵看为一个整体元素并移动他的位置,如此自然考虑到设置四重循环。
- 卷积应用是一大难点,也是基础题目的压轴之作。首先你要成功下载并配置好opencv软件因为主要问题是ppt教程中并未涉及配置路径后需要重启计算机的提醒,而我在不知情的情况下,最终才用另一种方法搞好:将opencv的bin文件中的三个dll文件全部移到C:Windows系统的文件中,这样的效果应与重启效果一致。在可以使用opencv之后,就可以利用其中包含的功能进行图像与矩阵的相互转化了。在进行图像处理时,自然想到将图像的像素值变成数组,再利用数组的卷积变换后重新变成图像。而数组与图像(Mat和IplImage类型)之间的相互转化是一大问题,然而查阅文献之后只要看懂、记住固定模板就能成功使用。
- 在自认为成功按照题目要求并完美地实现图像处理后,等到输出时才发现,人物如同鬼一般。如下图:img1.png 我们发现除了第一和第二张图是合理的,中间四张图都显然出现了问题。因此我想到看看第一张图对应的矩阵数值是什么样的,我在数组转换回图片的前一步,加上cout每一项数组数值的操作,于是看到输出了如同天花乱坠般的数字。这里有一张原图像的数组示例 卷积后也是类似的样子,只不过所有数据均在0到255之内,事实上灰度值就是只在0到255分布。因此自然发现中间那几个乱图对应的数组数值既有负的,又有超出255的。这时可以构造灰度值在0到255内的灰度拉伸函数(主要功能就是用255乘上一个小于一的数,对应于每一个像素点的新值),在每一次输出图像前都事先拉伸整理灰度值,就可以得到理想的图片了。
- 加分项的二值化事实上有不止一种算法可以实现,而本次作业要求使用大津法(OTSU),主要难点在于阈值的确定,确定了阈值就自然将所有点分为大于和小于两类,一类是黑、一类是白。阈值的计算实际上是一个函数求极大值的问题,这个函数包括每一个像素所占比例,两大类像素所占比例等五个形参,而这五个形参又都与我们寻找的i值(就是阈值)相关,因此,对于这样一个参数方程,我们遍历所有的i,比较出最大的函数值所对应的i值,这个i就是要寻找的阈值。我们再调用这个寻找阈值的函数并返回阈值,带入到otsu函数中去,使用opencv库中的cvThreshold函数,选择THRESH_BINARY(作用为将大于阈值的像素赋值为255(白色),将小于阈值的像素赋值为0(黑色)),代入所需要的实参就可以输出二值化demolena图像。
- 在应用了二值化技术之后,又遇到了如何将背景设置为黑色而使前景图不变的问题。这二者的区别在于本应变为0的像素点不变,在cvThreshold函数调用THRESH_TOZERO就可以实现该功能。
- 最直观的感受就是要自学的东西好多。就算在百度上寻找的到相应的代码,也是不能直接复制粘贴的。因为每个人写局部代码的前提都有所不同,只有看懂了代码的含义,明白了实现思路,才能真正化为己用,变成自己的代码。
- Opencv自带了许多库函数,他们都是以cv为前缀命名的。合理的使用这些库函数可以大大化简程序,并且易于阅读。
- 对图像(矩阵)卷积操作的理解可以从一开始失败的图像中找到思路,比如B2卷积核中间一行都是零,而对应的第二个图像的纹理就是横向分布的;B3卷积核中间一列都是零,对应的第三个图像的纹理就是纵向分布的;B5同理。所以展示出来的效果就好像是不同方位的光线照射出来的效果一般。——这是直观理解。
- 另外,我还对opencv中Mat和IplImage两种类型存在一定的不解。虽然数组类型、Mat和IplImage这三者可以相互转化,但是我对Mat内部的库函数还不甚了解,导致在二值化的时候只能选用IplImage。