记录自己用python加opencv实现的图像处理的入门操作,各种平滑去噪滤波器的实现。
包括有:产生的椒盐噪声、高斯噪声等等,以及使用的中值滤波、平均滤波、高斯滤波等等。
分成了两部分来实现:一是自编写函数来实现,二是调用opencv中的相应函数,对比效果。
噪声的产生:分别是椒盐噪声和高斯噪声,原理的话可以参考别人的博客或我之后再补充,噪声就是在原来的图像上以一定的特殊规律给图像增添一些像素,使图像变得模糊等等。
1.噪声的自编写
椒盐噪声:
输入图像和自定义的噪声阈值,输出处理后的图像
# 向图片中添加椒盐噪声
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] = 0elif randomnum > thres: # 如果随机数大于胡椒噪声阈值1-0.1,则将此位置灰度级的输出设为255,即添加胡椒噪声output[i][j] = 255else: # 如果随机数处于两者之间,则此位置的灰度级的值等于原图的灰度级值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.0else: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-aoutput[i][j][1] = 255-boutput[i][j][2] = 255-cfor 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] = aoutput[i][j][1] = boutput[i][j][2] = creturn output
2.平滑去噪滤波器的自编写
设计了均值滤波、中值滤波、高斯滤波,可分别对应处理以上的三种噪声,效果较好。
具体的对应情况可自己比较一下哦。
中值滤波:
# 中值滤波 a为要处理的图像 windowsize为采用的模版大小
def medianfliter(a, windowsize):output = aif 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] = valueelif 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 = aif 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]]) / 156kernel = np.zeros(im.shape)kernel[:b.shape[0], :b.shape[1]] = bfim = np.fft.fft2(im)fkernel = np.fft.fft2(kernel)fil_im = np.fft.ifft2(fim * fkernel)return abs(fil_im).astype(int)
3.自编写函数的主程序
我用到的包有: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()
效果展示为:
4.opencv实现噪声+滤波器
以opencv中的函数实现各种噪声的产生和滤波器的编写更为简单,基本一行代码就可以实现调用,以下是我的整个程序:
# 图像去噪平滑滤波
# 使用opencv的自带函数实现,与自编写作比较
# 产生椒盐噪声,高斯噪声等
# 使用中值滤波,平均滤波,高斯滤波,方框滤波import numpy as np
import cv2
import matplotlib.pyplot as plt# 加噪声
def noise(img):out = imgrows, cols, chn = img.shapefor i in range(5000):x = np.random.randint(0, rows)y = np.random.randint(0, cols)out[x, y, :] = 255return outif __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()
效果展示为: