对指定图像的复原与增强
原图像 1-1
实验流程如下:
根据观察不难得出图像中存在脉冲噪声,故而应用中值滤波器进行滤波,去除脉冲噪声。
对于脉冲噪声的滤除不限于滤波方法,笔者曾尝试过其他思路,但是由于效果较中值而言略显粗糙,仅作为附加方案在下文叙述。
而对于图像中的亮线,采取截短做Fourier Transform进行频域滤波的方法,尝试进行复原。
关于该方法做如下说明:
根据亮线的形态及对于空间波的认知来说,我们可以认为这些亮线是由某一频率的空间波构成,也就是说,我们可能在频域上进行滤除。但是这里要提出一个问题:现有的FT是否可以处理构成亮线的空间波频率?
众所周知,Fourier Transform是我们了解频域信息的重要手段,但是该方法仍不是完美的,我们须注意到,Fourier Transform所得到的频域信息不包含原图像的空间信息(关于这一点,FT的移不变就是很好的例证),强调的是全局性的频率信息。FT将图像近似等效的分解为一系列周期的、在图像中均匀的空间波的加和,所以对任意分量的幅度的改动都势必影响整个图像,由于空间波的连续性,我们无法仅指定一个区域内的幅度发生改变。综上,我们需要对FT进行优化:加入空间信息并获得频谱。
幸运的是,虽然我们难以在精巧的FT上引入空间信息,但是我们可以对图像进行改动,也就是将图像截取后进行FT,此时我们对频域的处理就不会影响截取区域以外的位置,间接的实现空间信息的引入。
截短FT结果 1-2
关于脉冲噪声处理的其他方案:
对于脉冲噪声来说,中值滤波有这较好的效果,但是也不可避免的对图像造成了模糊效果。在细究滤波过程可以发现,中值滤波实际上存在许多不必要的操作:即使是非噪声点依旧以中值替换!所以我们以这一点进行优化:能否确定图像中噪点位置?
根据脉冲噪声的特性,其与邻域内的像素点有着极其显著的差值,或者说有着与正常像素明显的边缘,因此可以尝试采用边缘检测对噪点进行判断。这里注意,边缘检测得出的不仅是噪点,也包括正常图像的边缘,尽管边缘不应该被处理,但是相对于中值来说已经缩减相当大的误处理范围了,所以这里将图像边缘一并进行去噪处理
在我们得到噪点位置之后,我们需要知道在这一点原图像的像素值。根据信息论我们可以做出如下假设:存在某一邻域上的线性组合,使得该点的像素值可以被表示。基于此假设,我们可以利用邻域内其他像素点进行推测。由于笔者水平有限,这里采用自适应窗和非线性拟合的效果会更好。
实验效果见实验结果 附
在查阅相关材料后,发现可以通过腐蚀处理亮线,大致流程如下:
腐蚀操作首先需要确定待腐蚀边界,因此,仍然对图像进行边缘检测
边缘检测 1-3
后依旧边缘信息将图像分成若干联通区域
连通集 1-4
取面积最大的两块连通集作为图像掩码,并将该掩码取反,使包括待处理区域布尔值为真
图像掩码 1-5
根据观察可知待去除部分为矩形,假定一行中半数像素的掩码为真,即判定为待处理区域。确定处理区域后,进行腐蚀操作,即可修复亮线
1.程序代码
import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
import tool as tk # 原码见文末
def showimg(name, scr):
length = len(scr)
for i in range(length):
cv.imshow(name[i], scr[i])
def w(name, src):
cv.imwrite('../img/'+name+'.jpg', src)
def different(img1, img2):
cv.imshow('different', np.array((img1 - img2), dtype=np.uint8))
cv.waitKey(0)
def solution1(img):
recover = np.array(img, dtype=np.uint8)
mask = np.empty_like(recover, dtype=np.uint8)
time = 3
for i in range(time):
mask = tk.detectedge(recover, 80)
recover = tk.interpolation(recover, mask, method='bilinear')
name = ['img', 'mask', 'res']
showimg(name, [img, mask, recover])
cv.waitKey(0)
cv.destroyAllWindows()
def solution2(img):
img = cv.cvtColor(img, cv.COLOR_RGB2GRAY)
length, width = img.shape
slice_length, slice_width = 40, width
mask = np.ones((slice_length, slice_width))
for i in range(slice_length):
if i in range(np.int(slice_length / 2) - 1, np.int(slice_length / 2) + 2):
continue
mask[i, np.int(slice_width / 2)] = 0
res = tk.ppf(img, slice_length, mask, begin=5, size=1)
res = tk.score(res, method='mid')
img_back = np.array(res, dtype=np.uint8)
eq_img_back = cv.equalizeHist(img_back)
tk.histogram([img_back, eq_img_back])
cv.imshow('res' ,eq_img_back)
cv.waitKey(0)
cv.destroyAllWindows()
def get_area(edge):
vis = np.zeros_like(edge, dtype=np.bool)
area_mark = np.zeros_like(edge, dtype=np.int)
height, width = edge.shape
area_kind, area = (1, [0])
move = np.array([[0, 1], [0, -1], [1, 0], [-1, 0]], dtype=np.int)
check = lambda x, y: x >= 0 and y>= 0 and x < height and y < width and not vis[x, y] and edge[x, y]==0
for x in range(height):