黑帽(Black Hat),又称“底帽”运算,其结果图像为闭运算图与原图像的差,即:
dest=close(src,kernal)-src
由于闭运算是先膨胀和腐蚀,因此闭运算会去除图像中的小黑点,同时也会扩大图像前景轮廓的范围,实际上也就是放大了图像前景色区域,因此从闭运算图减去原图的运算结果突出了比原图轮廓周围的区域更暗的区域,此外黑帽还能得到图像内部的小孔,或者前景色中的小黑点。因此黑帽运算可以用于提取亮背景中的细小暗物体。
黑帽在OpenCV-Python的调用语法如下:
morphologyEx(src, CV2.MORPH_BLACKHAT, kernel, dst=None, anchor=None, iterations=None, borderType=None, borderValue=None)
关于morphologyEx的介绍请参考《OpenCV-Python图像形态变换概述及morphologyEx函数介绍: https://blog.csdn.net/LaoYuanPython/article/details/109556425》。
在如下图像(文件名:带水印中国地图.jpg):
在上述地图中存在两行比较淡的水印:“老猿Python”、“https://blog.csdn.net/LaoYuanPython”。
import cv2
import numpy as np
from opencvPublic import print2DMatrix,preparePreviewImg,previewImgList,previewImg
def morphologyExTest(imgObj,imgTitle=''):
if isinstance(imgObj, str):
img = cv2.imread(imgObj)#, cv2.IMREAD_GRAYSCALE)
if img is None:
img = cv2.imdecode(np.fromfile(imgObj, dtype=np.uint8), -1)
imgTitle = imgTitle+imgObj+': '
else:
imgTitle = imgTitle + ': '
if len(img.shape)==2: channel = 1
else: channel = img.shape[2]
if channel==3:
img = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
elif channel==4:
img = cv2.cvtColor(img,cv2.COLOR_BGRA2GRAY)
ksize = (3,3)
kernal = cv2.getStructuringElement(cv2.MORPH_RECT,ksize )
#preparePreviewImg(img, imgTitle + '原图')
preparePreviewImg(cv2.morphologyEx(img, cv2.MORPH_BLACKHAT, kernal),imgTitle+f'黑帽,矩形核大小{ksize}')
def morphologyTest():
morphologyExTest(r'f:\pic\带水印中国地图.jpg')
previewImgList()
morphologyTest()
上面代码中使用的图像预览的函数请见《OpenCV-Python图像运算变换处理:开运算和闭运算以及不同核矩阵的影响分析: https://blog.csdn.net/LaoYuanPython/article/details/109984045》的介绍。
经上述代码处理后,该原图黑帽运算的结果图像如下:
可以看到黑帽运算后提取到了一副去除水印的完整地图图片。
将上述代码中处理的原图替换为如下图像(文件名:白底蓝线浅水印.jpg),并将核大小调整为7*7:
得到如下黑帽结果图像:
可以看到水印文字被去除,但留下了部分缝隙。
对上述图像进行一次闭运算,得到如下图像:
可以看到黑帽运算中的部分缝隙得到了部分填充。上述处理过程如果使用(3,3)大小的核,则无法达到上述的效果,相关线段无法提取出来。
以上述图像对应的灰度图像作为mask再将原图像进行自与运算,就可以得到原图像中除去水印的效果图如下:
通过调整核大小以为9*9时,上述线段交叉处的黑色部分可以填充为蓝色,效果会更好一些。
上图看起来都是黑色,对该图乘以4倍因子得到如下图:
可以看到提取的是原图中白色部分的周边边缘,该效果很好地体现了黑帽运算的功能。
前面介绍了,黑帽运算可以用于提取提取亮背景中的细小暗物体,通过案例3可以看到这点,但为什么反而可以在案例1和2中用于去除图像中的浅色水印呢?我们以第二个例子为例来解释:
首先我们来看看原图进行闭运算的结果图,如下
可以看到闭运算后,由于整图的亮背景色,导致闭运算后,原图的那些线条和文字几乎接近不可见,但并不是都消失了,都该图乘以0.5降低整体亮度后,得到如下图像:
可以看到文字信息不见了,但线条还在。由此可以说明,作为水印的文字信息在闭运算中被膨胀清除了,而线条在闭运算中虽然提高了亮度但还是存在的,只是与周边的颜色差异很小,无法看清,当乘以0.5后,这个差异就显现出来了,由此可见该线条的颜色灰度值接近255。
由于黑帽是闭运算结果图减原图像,由于原图像中背景色主色为白色,其像素灰度值值为255,而线条颜色为蓝色,对应灰度值为127.5(计算方法请参见《图像处理术语解释:灰度、色相、饱和度、亮度、明度、阿尔法通道、HSL、HSV、RGBA、ARGB和PRGBA以及Premultiplied Alpha(Alpha预乘)等基础概念详解》),闭运算结果图减原图像后,得到灰度值接近于255-127.5=127.5,因此黑帽运算后线条能比较清晰的显示。
因此通过黑帽运算后,背景色变成了黑色,线条比较清晰的展示,文字消失了,从而实现了水印文字的去除。从上面的介绍可以得出,水印文字之所以能消除,是因为水印文字颜色的灰度值与背景白色的灰度值相差不大。
本文简单介绍了黑帽的概念、原理和作用,以及OpenCV-Python的具体实现,并提供了两个利用黑帽去除图像水印的案例和一个提取白色图像周边黑色轮廓的案例,通过黑帽的结果图像,再作为mask去与原图像进行运算,即可以得到原图像中去除水印后的亮色图像部分。黑帽运算和顶帽类似,用一个结构元素(核矩阵)通过闭操作从一副图像中删除前景色中比较暗的部分,留下来前景色中相对比较亮的细小部分,就是从图像的亮背景上提取细小的暗物体,黑帽这个特性也可以用于校正不均匀光照的影响(请参考博文:《光照不均匀图像分割技巧2——顶帽变换和底帽变换》)。
如果阅读本文于您有所获,敬请点赞、评论、收藏,谢谢大家的支持!
下面是老猿博文中与形态变换相关的博文列表:
更多OpenCV-Python的介绍请参考专栏《OpenCV-Python图形图像处理 》
专栏网址:https://blog.csdn.net/laoyuanpython/category_9979286.html
老猿的付费专栏《使用PyQt开发图形界面Python应用 》(https://blog.csdn.net/laoyuanpython/category_9607725.html)专门介绍基于Python的PyQt图形界面开发基础教程,付费专栏《moviepy音视频开发专栏》 (https://blog.csdn.net/laoyuanpython/category_10232926.html)详细介绍moviepy音视频剪辑合成处理的类相关方法及使用相关方法进行相关剪辑合成场景的处理,两个专栏都适合有一定Python基础但无相关知识的小白读者学习。
付费专栏文章目录:《moviepy音视频开发专栏文章目录》(https://blog.csdn.net/LaoYuanPython/article/details/107574583)、《使用PyQt开发图形界面Python应用专栏目录 》(https://blog.csdn.net/LaoYuanPython/article/details/107580932)。
对于缺乏Python基础的同仁,可以通过老猿的免费专栏《专栏:Python基础教程目录》(https://blog.csdn.net/laoyuanpython/category_9831699.html)从零开始学习Python。
如果有兴趣也愿意支持老猿的读者,欢迎购买付费专栏。