记录自己用python加opencv实现的图像处理的入门操作,各种平滑去噪滤波器的实现。
包括有:产生的椒盐噪声、高斯噪声等等,以及使用的中值滤波、平均滤波、高斯滤波等等。
分成了两部分来实现:一是自编写函数来实现,二是调用opencv中的相应函数,对比效果。
噪声的产生:分别是椒盐噪声和高斯噪声,原理的话可以参考别人的博客或我之后再补充,噪声就是在原来的图像上以一定的特殊规律给图像增添一些像素,使图像变得模糊等等。
椒盐噪声:
输入图像和自定义的噪声阈值,输出处理后的图像
# 向图片中添加椒盐噪声
def salt_pepper_noise(image, prob): # prob:盐噪声阈值,由用户自己决定
output = np.zeros(image.shape, np.uint8)
thres = 1 - prob # 胡椒噪声阈值
for i in range(image.shape[0]): # 遍历整个图片的灰度级
for j in range(image.shape[1]):
randomnum = random.random() # 生成一个随机0-1之间的随机数
if randomnum < prob: # 如果随机数大于盐噪声阈值0.1,则将此位置灰度级的值设为0,即添加盐噪声
output[i][j] = 0
elif randomnum > thres: # 如果随机数大于胡椒噪声阈值1-0.1,则将此位置灰度级的输出设为255,即添加胡椒噪声
output[i][j] = 255
else: # 如果随机数处于两者之间,则此位置的灰度级的值等于原图的灰度级值
output[i][j] = image[i][j]
return output
高斯噪声:
输入图像,自定义的参数:均值、方差,输出的是处理后的图像
# 向图片中添加高斯噪声
def gasuss_noise(image, mean=0, var=0.001): # mean : 均值,var : 方差
image = np.array(image/255, dtype=float)
noise = np.random.normal(mean, var ** 0.5, image.shape) # 使用numpy库中的函数生成正态分布矩阵,对应数据分别为概率均值,概率标准差,图像的大小
output = image + noise # 输出结果为原图灰度级概率与噪声概率相加
output_handle = np.array([[[0]*3 for i in range(output.shape[1])] for i in range(output.shape[0])], dtype=float)
# 处理后最终输出矩阵将齐大小设置为与原图一样
if output.min() < 0: # 确定一个比较中间值
low_clip = -1.
else:
low_clip = 0.
for i in range (output.shape[0]): # 遍历整个三位矩阵
for j in range (output.shape[1]):
for k in range (output.shape[2]):
if output[i][j][k] < low_clip: # 将输出的概率矩阵内的值限定在(-1,1)范围内
output_handle[i][j][k] = low_clip # 使其之后*255变为灰度级时不会超出[0-255]的范围
elif output[i][j][k] > 1.0:
output_handle[i][j][k] = 1.0
else:
output_handle[i][j][k] = output[i][j][k] # 在最大值和最小值之间的不变
output = np.uint8(output_handle*255) # 将处理后的灰度级转化为[0-255]的整数级
return output
加性噪声:
# 向图片中添加加性噪声
def addrandom_noise(image,prob=0.1):
output = image # 将原始图像数据拷贝至输出矩阵
n = random.randint(1, 1000) + int(prob*20000)
for k in range(n-500):
a = random.randint(0, 50)
b = random.randint(0, 50)
c = random.randint(0, 50)
i = random.randint(0, image.shape[0]-1)
j = random.randint(0, image.shape[1]-1)
output[i][j][0] = 255-a
output[i][j][1] = 255-b
output[i][j][2] = 255-c
for k in range(n):
a = random.randint(0, 50)
b = random.randint(0, 50)
c = random.randint(0, 50)
i = random.randint(0, image.shape[0]-1)
j = random.randint(0, image.shape[1]-1)
output[i][j][0] = a
output[i][j][1] = b
output[i][j][2] = c
return output
设计了均值滤波、中值滤波、高斯滤波,可分别对应处理以上的三种噪声,效果较好。
具体的对应情况可自己比较一下哦。
中值滤波:
# 中值滤波 a为要处理的图像 windowsize为采用的模版大小
def medianfliter(a, windowsize):
output = a
if windowsize == 3 :
output1 = np.zeros(a.shape, np.uint8)
for i in range(1, output.shape[0]-1): # 求齐周围9个方格与模版进行冒泡排序
for j in range(1, output.shape[1]-1):
value1 = [output[i-1][j-1], output[i-1][j], output[i-1][j+1], output[i][j-1], output[i][j], output[i][j+1], output[i+1][j-1], output[i+1][j], +output[i+1][j+1]]
np.sort(value1) # 对这九个数进行排序
value = value1[4] # 中值为排序后中间这个数的正中间
output1[i-1][j-1] = value
elif windowsize == 5:
output1 = np.zeros(a.shape, np.uint8)
for i in range(2, output.shape[0]-2): # 求齐周围25个方格与模版进行卷积
for j in range(2, output.shape[1]-2):
value1 = [output[i-2][j-2],output[i-2][j-1],output[i-2][j],output[i-2][j+1],output[i-2][j+2],output[i-1][j-2],output[i-1][j-1],output[i-1][j],output[i-1][j+1],\
output[i-1][j+2],output[i][j-2],output[i][j-1],output[i][j],output[i][j+1],output[i][j+2],output[i+1][j-2],output[i+1][j-1],output[i+1][j],output[i+1][j+1],\
output[i+1][j+2],output[i+2][j-2],output[i+2][j-1],output[i+2][j],output[i+2][j+1],output[i+2][j+2]]
value1.sort() # 对这九个数进行排序
value = value1[12] # 中值为排序后中间这个数的正中间
output1[i-2][j-2] = value # 将计算结果填入原本位置
else :
print('模版大小输入错误,请输入3或5,分别代表3*3或5*5模版!')
return output1
均值滤波:
# 均值滤波 a为要处理的图像 windowsize为采用的模版大小
def meanflite(a, windowsize):
output = a
if windowsize == 3:
window = np.ones((3, 3)) / 3 ** 2 # 生成3*3模版
output1 = np.zeros(a.shape, np.uint8)
for i in range(1, output.shape[0] - 1): # 求齐周围9个方格与模版进行卷积
for j in range(1, output.shape[1] - 1):
value = (output[i - 1][j - 1] * window[0][0] + output[i - 1][j] * window[0][1] + output[i - 1][j + 1] *
window[0][2] + \
output[i][j - 1] * window[1][0] + output[i][j] * window[1][1] + output[i][j + 1] * window[1][
2] +\
output[i + 1][j - 1] * window[2][0] + output[i + 1][j] * window[2][1] + output[i + 1][j + 1] *
window[2][2])
output1[i - 1][j - 1] = value # 将计算结果填入原本位置
elif windowsize == 5:
window = np.ones((5, 5)) / 5 ** 2 # 生成5*5模版
output1 = np.zeros(a.shape, np.uint8)
for i in range(2, output.shape[0] - 2): # 求齐周围25个方格与模版进行卷积
for j in range(2, output.shape[1] - 2):
value = (output[i - 2][j - 2] * window[0][0] + output[i - 2][j - 1] * window[0][1] + output[i - 2][j] *
window[0][2] + output[i - 2][j + 1] * window[0][3] + output[i - 2][j + 2] * window[0][4] + \
output[i - 1][j - 2] * window[1][0] + output[i - 1][j - 1] * window[1][1] + output[i - 1][j] *
window[1][2] + output[i - 1][j + 1] * window[1][3] + output[i - 1][j + 2] * window[1][4] + \
output[i][j - 2] * window[2][0] + output[i][j - 1] * window[2][1] + output[i][j] * window[2][
2] + output[i][j + 1] * window[2][3] + output[i][j + 2] * window[2][4] + \
output[i + 1][j - 2] * window[3][0] + output[i + 1][j - 1] * window[3][1] + output[i + 1][j] *
window[3][2] + output[i + 1][j + 1] * window[3][3] + output[i + 1][j + 2] * window[3][4] + \
output[i + 2][j - 2] * window[4][0] + output[i + 2][j - 1] * window[4][1] + output[i + 2][j] *
window[4][2] + output[i + 2][j + 1] * window[4][3] + output[i + 2][j + 2] * window[4][4])
output1[i - 2][j - 2] = value # 将计算结果填入原本位置
else:
print('模版大小输入错误,请输入3或5,分别代表3*3或5*5模版!')
return output1
高斯滤波:
ef gaussian(im):
im = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
b = np.array([[2, 4, 5, 2, 2],
[4, 9, 12, 9, 4],
[5, 12, 15, 12, 5],
[4, 9, 12, 9, 4],
[2, 4, 5, 4, 2]]) / 156
kernel = np.zeros(im.shape)
kernel[:b.shape[0], :b.shape[1]] = b
fim = np.fft.fft2(im)
fkernel = np.fft.fft2(kernel)
fil_im = np.fft.ifft2(fim * fkernel)
return abs(fil_im).astype(int)
我用到的包有:numpy、matplotlib.pyplot、cv2、random
主程序很好理解,读入原图,再对原图调用各种函数进行处理,再以子图的形式展示出来。
if __name__ == "__main__":
image = cv2.imread('whl.jpg')
plt.subplot(4, 2, 1)
plt.imshow(image)
plt.axis('off')
plt.title('Original')
salt = salt_pepper_noise(image, 0.05)
plt.subplot(4, 2, 2)
plt.imshow(salt)
plt.axis('off')
plt.title('salt')
gauss = gasuss_noise(image)
plt.subplot(4, 2, 3)
plt.imshow(gauss)
plt.axis('off')
plt.title('gauss')
random = addrandom_noise(image)
plt.subplot(4, 2, 4)
plt.imshow(random)
plt.axis('off')
plt.title('random')
median = medianfliter(salt, 3)
plt.subplot(4, 2, 5)
plt.imshow(median)
plt.axis('off')
plt.title('median')
mean = meanflite(random, 3)
plt.subplot(4, 2, 6)
plt.imshow(mean)
plt.axis('off')
plt.title('mean')
gaussout = gaussian(gauss)
plt.subplot(4, 2, 7)
plt.imshow(gaussout)
plt.axis('off')
plt.title('gaussout')
plt.show()
以opencv中的函数实现各种噪声的产生和滤波器的编写更为简单,基本一行代码就可以实现调用,以下是我的整个程序:
# 图像去噪平滑滤波
# 使用opencv的自带函数实现,与自编写作比较
# 产生椒盐噪声,高斯噪声等
# 使用中值滤波,平均滤波,高斯滤波,方框滤波
import numpy as np
import cv2
import matplotlib.pyplot as plt
# 加噪声
def noise(img):
out = img
rows, cols, chn = img.shape
for i in range(5000):
x = np.random.randint(0, rows)
y = np.random.randint(0, cols)
out[x, y, :] = 255
return out
if __name__ == "__main__":
image = cv2.imread('whl.jpg')
plt.subplot(3, 2, 1)
plt.imshow(image)
plt.axis('off')
plt.title('Original')
noise_img = noise(image)
plt.subplot(3, 2, 2)
plt.imshow(noise_img)
plt.axis('off')
plt.title('noise')
# 均值滤波
result1 = cv2.blur(noise_img, (5, 5))
plt.subplot(3, 2, 3)
plt.imshow(result1)
plt.axis('off')
plt.title('mean')
# 方框滤波
result2 = cv2.boxFilter(noise_img, -1, (5, 5), normalize=1)
plt.subplot(3, 2, 4)
plt.imshow(result2)
plt.axis('off')
plt.title('box')
# 高斯滤波
result3 = cv2.GaussianBlur(noise_img, (3, 3), 0)
plt.subplot(3, 2, 5)
plt.imshow(result3)
plt.axis('off')
plt.title('gaussian')
# 中值滤波
result4 = cv2.medianBlur(noise_img, 3)
plt.subplot(3, 2, 6)
plt.imshow(result4)
plt.axis('off')
plt.title('median')
plt.show()