编程马拉松 HACKATHON 2020 · TEAM24
完整的代码下载:https://github.com/hawkhai/hawkhai.github.io/tree/master/source/marathon
为了不那么占内存,以更好的演示效果,代码重新整理了一遍。
输入图片有:
cv2 读入的图片是 BGR 顺序。
图片读入后是一个三维矩阵。
将彩色负片转为彩色正片,矩阵运算,255 减一下,就是答案。
# 将彩色负片转为彩色正片
def phase1(inputImgPath: str, outImgPath: str):
img = kalgorithm.imgRead(inputImgPath)
img = 255 - img
kalgorithm.imgSave(outImgPath, img)
输入底片不正,需要先寻边调整。 图片矫正。图片输入不正的情况,方法很多,这里是:先剪裁,然后旋转矫正,最后再剪裁。
每种滤波算法都有自己的特点。
## prewitt vertical kernel 提取竖直边缘
[[-1., -1., -1.],
[ 0., 0., 0.],
[ 1., 1., 1.]]
## prewitt horizontal kernel 提取左右边缘
[[-1., 0., 1.],
[-1., 0., 1.],
[-1., 0., 1.]]
## Sobel vertical 提取竖直边缘
[[ 1., 2., 1.],
[ 0., 0., 0.],
[-1., -2., -1.]]
## Sobel horizontal 提取左右边缘
[[1., 0., -1.],
[2., 0., -2.],
[1., 0., -1.]]
均值滤波器使用网格内像素的平均值。图片更模糊了。
中值滤波器是一种可以使图像平滑的滤波器。有的噪点没了。
高斯滤波器是一种可以使图像平滑的滤波器,用于去除噪声。图片更模糊了。
GaussianFilter Kernel=5,这些数字的和刚好是 1.0。
[[0.0097565 0.02370077 0.03186045 0.02370077 0.0097565 ]
[0.02370077 0.0575746 0.07739634 0.0575746 0.02370077]
[0.03186045 0.07739634 0.10404229 0.07739634 0.03186045]
[0.02370077 0.0575746 0.07739634 0.0575746 0.02370077]
[0.0097565 0.02370077 0.03186045 0.02370077 0.0097565 ]]
不同的插值算法。越高级的算法越圆润,越耗时间,越基础的算法马赛克效果越明显。
三维图更明显,可以看到每种插值算法的特点。
phase2_interpolate_Lanczos 实现了 Lanczos 算法。
编译好的 lanczos.exe 已入库,需要 opencv_world3411d.dll 才能跑起来。
空域算法比较简单,直接用算子套上去算一下就可以了。算子求和是 1。
[ 0, -1, 0],
[-1, 5, -1],
[ 0, -1, 0],
用到傅里叶变换。低频是轮廓,高频是细节。用到高频提升滤波器。 将高频加强和直方图均衡相结合是得到边缘锐化和对比度增强的有效方法。[频域图像增强-锐化]
傅里叶的原理和过程,可以参考写的另外一篇文章。傅里叶变换
可以编程,显示这个 Gaussian 滤波函数的可视化。
和原图对比,效果还行。
图片噪点去除。这个噪点的特点,通过定义核(kernel)的大小,中值滤波可以很好的修复图片了。
OpenCV 实现了 INPAINT_TELEA : Fast Marching Method based 算法,INPAINT_NS : Navier-Stokes based Inpainting 算法。[OpenCV Inpainting] / [OpenCV 图像修复]
我们简单的实现了简易修复算法:先二值化,找到水印位置,然后根据位置,用最近邻算法填充。 下载了一个 TELEA 算法的 Python 实现,效果更好,但是没用它。
Otsu Binarization,大津二值化算法(Otsu's Method)。也被称作最大类间方差法。
以 B 结构中心点为准心,在 A 中找能满足 B 结构的点即为腐蚀。 把 A 结构的每个点放到 B 中心点,以 B 结构外扩即为膨胀。 开操作表示先腐蚀后膨胀;闭操作表示先膨胀后腐蚀。
一般用来扩充边缘或填充小的孔洞。
可用来提取骨干信息,去掉毛刺,去掉孤立的像素。
先腐蚀再膨胀,可以消除小物体或小斑块。分裂,毛刺去掉。 先腐蚀后膨胀的过程。开运算可以用来消除小黑点,在纤细点处分离物体、平滑较大物体的边界的同时并不明显改变其面积。
先膨胀再腐蚀,可用来填充孔洞。弥合,毛刺保留。 先膨胀后腐蚀的过程。闭运算可以用来排除小黑洞。
1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1
这个算子很长条,巧妙运算,可以过滤出海平线。
# 用一个 81 长的横线腐蚀一次,只剩下很长横线部分了。
out = morphologyErodeLine(out, 1, linelen=40)
# 用一个 81 长的横线膨胀一次,再把横线补全一下。
out = morphologyDilateLine(out, 1, linelen=40)
天空识别。完成天空替换。有倒影,有剪影。
我们把色彩变换到 HSV,然后做一个直方图,可以准确看到颜色分布情况,最高尖尖就是蓝色天空还海水部分,也是整张图的大部分颜色集中的地方。
8 比特位图像的最低阶比特对人眼感知几乎没有影响,因此,可以将水印图像的高阶比特位“插入”在衬底的低阶比特位中。\(f_w = 4(\frac{f}{4}) + \frac{w}{64}\)
LSB 水印非常脆弱,诸如裁剪、旋转、缩放,图像压缩等操作可以轻易破坏该水印。水印
有空了,单独写一篇文章。 https://github.com/hawkhai/hawkhai.github.io/blob/master/source/marathon/src/lib/watermark.py
为了计算速度,一上来把 3 倍大图缩小回去,等处理完了,最后在变大三倍。
首先修复图片,不再累述,然后用上面的 prewitt & sobel 算子计算整个图的边缘。
通过自定义的算子,分离出海平线,可以发现是倾斜的。
根据倾斜角度,矫正胶片,同时修复边缘。再计算出图片边缘,同时用水平投影法计算出海平线位置。
使用色彩追踪和形态学运算得到图像中感兴趣区域,可以很准确的分离出渔女部分,贴回原图,二值化,把黑乎乎的小岛也准确识别出来。 用闭运算处理一下毛刺,再用腐蚀把渔女变圆润一点。对分离出来的 mask 做一次均值滤波,让接头不那么生硬。
finalimage = newsky * masksky + imgsrc * (1 - masksky)
outv = ((mirrorsky * maskwave * 0.35) + # 下面部分,天空倒影
(imgsrc * maskwave * 0.4) + # 下面部分,原图
(imgsrc * (1-maskwave) * 0.8)) # 其他部分
# 最后再把原图渔女抠出来降低曝光度贴上去。
outv = outv * (1-mask_fishergirl) + outvgril * mask_fishergirl
针对海水模板进行 7x7 的均值滤波。