CV大作业中的细节与思路
关于撤销
- V1.0 最拿衣服版本:
只支持一步撤销,在每次有新操作之前做一次 commit,将之前的图保存在专门的 backup 数组里。
关于灰度图
- 由于所有图片读取都是用 Qt 读取,读完自动转化成 RGB 三通道,所以不再单独讨论只有单通道的灰度图,处理灰度图的时候三通道相等。(后期可以拓展输出单通道的功能)
关于 alias
- Mat newImg = oldImg.clone();
解决
彩色图像处理
- 三通道分离:
将三通道的值全部改成指定通道的值(可进一步做成只有一个通道的灰度图)。 - 彩色转灰度:
公式:gray = (r * 299 + g * 587 + b * 114 + 500) / 1000
- HSV与色相/饱和度/亮度调节:
h,s,v 分别对应色相,饱和度和亮度。
通过 slide bar 实现。
h 对应的 slide bar 范围为 [0,360],直接将 bar 上读入的值赋给所有像素的 h 值。
s 和 v 对应的 slide bar 为增量模式,bar 的范围为 [-255,255],将 bar 上读入的值作为增量加到各个像素原本的值上,需要越界检查,否则图像失真不可恢复。
代数操作与几何操作
- 加法操作:
将第二张图加到第一张图上,需要指定两个 layer 和各自的权重。
还需要指定一个坐标(根据这个坐标在第一张图上选定 ROI ),这个坐标缺省值为(0,0)。
需要检测越界。 - 减法操作:
第一张图作为被减数,第二张图作为减数。
同样需要指定两个 layer 和选 ROI 的坐标,不实现加权。
需要检测越界。 - 乘法除法操作:
规定只有两张大小相同的图片才能相乘除,否则直接返回不做操作。
对应像素值相乘除。
然后为了防止像素值超过255或过小,运算完后要 /255 或 *255 。 - 双线性插值:
缩放和旋转操作都会用到双线性插值。原理如下:
原图缩放/旋转之后得到新的图像,遍历新图像的每个像素点,倒着计算回原图取得一个理论计算坐标(非整数),而像素只能表示整数的点,于是就取“包围”着理论计算点的四个整数像素点:
(x1, y1),(x1, y2), (x2, y1),(x2, y2), 其中 x2 = x1 + 1, y2 = y1 + 1 。
这四个点与中间夹着的理论点可以分割形成四个矩形,将着四个矩形的面积作为权重进行差分计算算出该点的像素值。
实现了封装函数专门计算双线性插值。
对比度调节
- 直方图:
rgb 三通道分别画直方图。
画的过程中线性映射,将统计出的直方图 list 中最大值映射成 256,每个灰度值画两个像素宽度,最终画成一张 512*256 大小的直方图。 - 直方图均衡化:
rgb 三通道分别统计直方图并进行运算。
后期测试发现 rgb 三通道分别计算均衡化的方法会导致彩色图像失真,调查原因:Histogram equalization is a non-linear process. Channel splitting and equalizing each channel separately is not the proper way for equalization of contrast. Equalization involves Intensity values of the image not the color components. So for a simple RGB color image, HE should not be applied individually on each channel. Rather, it should be applied such that intensity values are equalized without disturbing the color balance of the image. So, the first step is to convert the color space of the image from RGB into one of the color space which separates intensity values from color components. Some of these are:
HSV/HLS
YUV
YCbCr
Convert the image from RGB to one of the above mentioned color spaces. YCbCr is preferred as it is designed for digital images.Perform HE of the intensity plane Y. Convert the image back to RGB.
Canny 边缘检测
- canny 算法通过调整高斯滤波的力度和双阈值的数值可以起到不同的效果,就 Lena 的图片来说,经实验发现当双阈值分别为 30 和 80 时可以起到比较好的效果。下图为高斯滤波卷积核大小不同的效果对比图。(左,原图;中,双阈值30/80高斯核大小33;右,双阈值30/80高斯核大小55)当卷积核较小时,能获得较多细节,但是也较嘈杂;卷积核较大时,失去较多细节,但没有很多细线图像显得更清晰。
形态学操作
-
黑与白
白--255--1;黑--0--0;
所以膨胀和腐蚀操作所膨胀/腐蚀的区域都是白色区域。 -
击中击不中和粗化细化
输入 kernel 的意义不变,仍然是 1 - 白,0 - 黑。当击中击不中 match 的时候,就把对应的锚点记为黑(0),不 match 则记为白(255)。
细化作减法的时候如果击中击不中结果为黑(0),则减法结果为白(255);如果击中击不中结果为白(255),则减法结果为原图的值。
粗化作并集的时候如果击中击不中结果为黑(0),则并集结果为黑(0);如果击中击不中结果为白(255),则并集结果为原图的值。
在以上算法下,粗化细化的是黑色区域。
可用操作:比如当前有一副图左半边为白,右半边为黑。用卷积核 [100;100;100;] 去细化,可以使得黑白分界线向右推进(细化了黑色区域);而用卷积核 [110;110;110;] 去粗化,可以使得黑白分界线向左推进(粗化了黑色区域)。 这里卷积核的锚点默认为中心,也正因为如此上面两个操作的卷积核才必须有所区别。 -
形态学重构
用户给定两张等大图像 marker 和 mask,目标是 marker 向 mask 生长。
(1) 用 3*3 全 1 卷积核对 marker 做 dilation
(2)将(1)中得到的图像和 mask 做交操作(取较小的值)
(3) 重复(1)、(2)直到 marker 收敛
可用操作:将一张有噪音的图开操作去除噪音(但同时失去的部分细节),将这张图作为 marker,同时将有噪音的原图作为 mask,进行形态学重构,可恢复大部分细节但是不再生成过多噪音。 -
骨架提取与骨架重构
按照课本(冈萨雷斯)上的算法实现,但是提取出的骨架和 ppt 上的对比样例不完全一致。(见下图)
我认为两种效果都满足火烧草地的等距条件。
ppt 上的对比图
-
分水岭算法
通过调整梯度值可以调整分割的程度。梯度值过小会导致过分割。
原图
waterShed_10.png
waterShed_20.png
waterShed_30.png
waterShed_40.png
waterShed_50.png
附加内容
-
基于神经网络的手写数字识别
训练结果图
用 matlab 实现了基于一层 hidden layer 的全连通神经网络的手写数字识别,目标是识别手写的单个数字。
训练集取自 MNIST ,训练样本为 8000 张 28*28 像素的图像,训练出的模型对于 training set 的预测准确率在 80% 以上。
但是把训练的模型移植到 c++ 项目并尝试用该模型预测现场手写的数字时却出现了很大的误差,大多数情况不能正确预测。
训练集样本
误差原因分析: 我认为产生较大误差的原因是训练样本和最终预测的图片有较大差距。训练的样本为 28*28 像素,背景黑色字体白色。而我手写字体的照片分辨率很高,背景白色字体黑色 。我进行了裁剪,二值化,缩放等操作然后进行预测计算,这个过程导致了最终用于预测的图片与训练图片有了较大的差异(白色字体较细,不连续等,对比图如下)。
尝试预测的图片 -
Min/Max 运算
-
马赛克运算
-
伪彩色处理
-
色调分离处理
-
画笔功能,拾色器功能,橡皮擦功能
-
单步撤销功能
QUIZ 题目解答
流程为:
- 将彩色图片转成灰度图片。
- 将灰度图片做直方图均衡化处理。(这一步的原因时这张图的背景有较多全黑的部分,如果直接 otus ,阈值会被大量黑色部分干扰)
- 用 Otus 算法进行二值化。
// 2. 3. 两步也可以合成一步,用双阈值手动二值化。 - 将二值图像黑白颠倒。
- 用较大的全为 1 的 kernel(实验时用的时 9*9)进行开操作。目的是将长条状的血管当作噪声除去。
-
用 5. 得到的图片作为 marker ,4. 得到的图片作为 mask 进行形态学重构。目的是恢复 5. 操作损失的部分细节,同时不要重新引入血管噪声。
原图
step1_toGray.png
step2_Equalization.png
step3_Otsu.png
step4_binEx.png
step5_open.png
step6_reconstruction(final).png