前言
今天我们将学习如何通过一种“修复”的方法消除旧照片中的小噪音,笔画等。当然,经过我的测试你也可以将其用于削弱混杂了其他的颜色的图像。
实验背景
大多数人家都会有一些旧的的旧化照片,上面有黑点,一些笔触等。你是否曾经想过将其还原?我们不能简单地在绘画工具中擦除它们,因为它将简单地用白色结构代替黑色结构,这是没有用的。在这些情况下,将使用一种称为图像修复的技术。基本思想很简单:用附近的像素替换那些不良区域,使其看起来和邻近的协调。考虑下面显示的图像(摘自Wikipedia)。
同样的,今天我在这里也要进行一些拓展,采用我的方法也可以用于削弱混入了图像中的其他颜色。
获取图像的掩膜图
下面的图片是经过人脸检测后的图片,现在我并不想要它这个框。
运行下面的脚本进行颜色提取
import cv2
import numpy as np
import pyps.pyzjr.utility as zjr
def empty(a):
pass
path = 'AI.png'
cv2.namedWindow("TrackBars")
cv2.resizeWindow("TrackBars",640,250)
cv2.createTrackbar("Hue Min","TrackBars",58,179,empty)
cv2.createTrackbar("Hue Max","TrackBars",60,179,empty)
cv2.createTrackbar("Sat Min","TrackBars",73,255,empty)
cv2.createTrackbar("Sat Max","TrackBars",255,255,empty)
cv2.createTrackbar("Val Min","TrackBars",36,255,empty)
cv2.createTrackbar("Val Max","TrackBars",255,255,empty)
#经过测试得到的掩码58 60 73 255 36 255
while True:
img = cv2.imread(path)
#图像转化为HSV格式,H:色调S:饱和度V:明度
imgHSV = cv2.cvtColor(img,cv2.COLOR_BGR2HSV)
h_min = cv2.getTrackbarPos("Hue Min","TrackBars")
h_max = cv2.getTrackbarPos("Hue Max", "TrackBars")
s_min = cv2.getTrackbarPos("Sat Min", "TrackBars")
s_max = cv2.getTrackbarPos("Sat Max", "TrackBars")
v_min = cv2.getTrackbarPos("Val Min", "TrackBars")
v_max = cv2.getTrackbarPos("Val Max", "TrackBars")
print(h_min,h_max,s_min,s_max,v_min,v_max)
#创建一个蒙版,提取需要的颜色为白色,不需要的颜色为白色
lower = np.array([h_min,s_min,v_min])
upper = np.array([h_max,s_max,v_max])
mask = cv2.inRange(imgHSV,lower,upper)
imgResult = cv2.bitwise_and(img,img,mask=mask)
imgStack = zjr.stackImages(0.7,([img,imgHSV],[mask,imgResult]))
cv2.imshow("Stacked Images", imgStack)
cv2.waitKey(1)
注:import pyps.pyzjr.utility as zjr,此为我的私库函数,大家可以使用matplotlib.pyplot as plt代替此功能。
这里有关于HSV的一些介绍,下面是一些常见颜色的HSV值,大家可以参考着在轨迹栏中进行调整,顺序都是从上到下,具体还是要根据实际情况进行调整。
详解cv2.inpaint()
cv2.inpaint是用于图像修复的函数。它可以自动根据给定的掩膜(mask)来修复图像,即用图像中的其他部分来填充掩膜部分的像素。函数的语法如下:
dst = cv2.inpaint(src, inpaintMask, inpaintRadius, flags)
其中的参数的含义如下:
src
: 要修复的原始图像inpaintMask
: 修复图像的掩膜,即需要被修复的像素区域inpaintRadius
: 修复半径,即掩膜的像素周围需要参考的区域半径flags
: 修复算法的标志。有两个可选值:cv2.INPAINT_TELEA和cv2.INPAINT_NS。默认为cv2.INPAINT_TELEA。
其中,cv2.INPAINT_TELEA和cv2.INPAINT_NS分别代表基于快速行进算法(Fast Marching Method)和基于Navier-Stokes方程(Navier-Stokes equation)的修复算法,前者更快、后者更准确。
修补图像
接着,我们需要将上面脚本的这几行放进下面的测试代码中。
lower = np.array([h_min,s_min,v_min])
upper = np.array([h_max,s_max,v_max])
mask = cv2.inRange(imgHSV,lower,upper)
imgResult = cv2.bitwise_and(img,img,mask=mask)
将调整好的值,从控制台中copy给h_min, h_max, s_min, s_max, v_min, v_max
import cv2
import numpy as np
import pyps.pyzjr.utility as zjr
path = 'AI.png'
img = cv2.imread(path)
Grayimg = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
h_min, h_max, s_min, s_max, v_min, v_max = 58, 60, 73, 255, 36, 255
lower = np.array([h_min,s_min,v_min])
upper = np.array([h_max,s_max,v_max])
imgHSV = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
mask_black = cv2.inRange(imgHSV, lower, upper)
imgResult = cv2.bitwise_and(img,img,mask=mask_black)
dst = cv2.inpaint(img, mask_black, 10, cv2.INPAINT_TELEA)
mask_white = cv2.bitwise_not(mask_black)
stackimg=zjr.stackImages(0.7,([img,imgResult],[mask_white,dst]))
cv2.imshow("repair_img",stackimg)
cv2.imwrite("AI2.png",dst)
cv2.waitKey(0)
运行结果如下所示, 效果比较不错,整体看来只有头发那里有些许模糊。
改进建议
如果你有现成的掩膜图,那么去除的效果会更好;如果你需要遍历文件进行修改,所获得的HSV值并不适用于每一张图,建议单独进行处理。
改进方式:
- 修改cv2.inpaint()参数,修复半径可以在合适的范围内进行修改,修复算法的标志,有两种方式可选cv2.INPAINT_TELEA和cv2.INPAINT_NS,其特点可以看看上面给出的详解,实际应用中,需要两种都试试,并不是cv2.INPAINT_NS就对这种图更准确。
- 使用颜色提取脚本,可以将HSV值稍微调整大一些,可能会包含了一些其他的颜色,但对于我们的目标颜色(绿色)能够提取的更加完整,尤其是面对颜色比较复杂的场景,比如热力图,这个可以后期个人去尝试。
- 使用np切片的方法,对掩膜图特定的区域进行保护。
x_threshold = 500 mask_black[:, x_threshold:] = 0
- 如果是用于检测,对于部分不是很理想的图像,可以使用ps细致修改,当然这是你在用来我这个方法后,作为压箱底的措施。
总结
效果是达到了我的预期,本来按照我个人的想法也是将目标颜色的附近颜色进行替换,那这不得不遍历图像得像素点,但还好有Opencv中有inpaint()函数,得以实现本次实验。在这里我们就不讨论它的实现原理了,大家在CSDN上可以搜索到很多得资料。
![65873690adcb4ffbac283a8089807465.png](https://i-blog.csdnimg.cn/blog_migrate/bbab94422044fd7ccf01fd76f83c90f5.png)
实验效果图
2023年5月7日修正
出现了一个bug,今天在测试时,文字为白色遮盖了我原本的图像,当我对图像进行上面的操作时,发现文字没有被消去,反而变为了黑色,如果要去消除,还需要再进行一次黑色文字的颜色提取,再用图像修补才达到我的预期。