利用Python实现图像高斯滤波(模糊)


利用Python实现图像高斯滤波(模糊)_第1张图片

import cv2 as cv
import numpy as np

#传入灰度图像
#sigma是高斯分布的标准差,avr是均值
def makeNoise(img,sigma,avr):
    img2=img.copy()#使用副本,不用原本的
    row,col=img2.shape#row和col都是列表类型,代表行数,列数
    for x in range(0,row):
        for y in range(0,col):
            img2[x,y] = img2[x,y]+np.random.normal(avr,sigma**2,1)[0]
    return img2

#传入灰度图像
#kernel_size为奇数。sigmax为0时是程序根据公式计算得方差,不为0时代表指定标准差为sigmax
def guassianImgFilt(img,kernel_size,sigmax):
    row,col = img.shape#获得未添加边界前的大小信息
    
    #下面产生卷积核   
    kernel = np.zeros([kernel_size,kernel_size])
    center = kernel_size//2#整除
    
    #计算标准差
    if sigmax == 0:
        sigma = ((kernel_size-1)*0.5-1)*0.3+0.8
    else: 
        sigma = sigmax
    
    s = 2*(sigma**2)
    sum_val = 0
    for i in range(0,kernel_size):
        for j in range(0,kernel_size):
            x = i-center
            y = j-center#center-j也无所谓,反正权重是按到圆心距离算的,而且距离带平方了,正负无所谓,x**2+y**2的值代表了权重。
            kernel[i,j] = np.exp(-(x**2+y**2)/s)
            sum_val += kernel[i,j]
            #/(np.pi * s)
    sum_val = 1/sum_val
    #对卷积核归一化,确保卷积核之和为1
    kernel = kernel*sum_val#对于np.array来说是对应位置相乘。这里不要用除,最好是用乘以分之一的形式
    #以上是产生卷积核
    
    #计算图像边界需要添加的范围,扩充图像边界使得能遍历到原图像的每一个像素
    addLine = int((kernel_size-1)/2)#虽然addLine理应是整数,但存储类型是浮点,要转换类型
    img = cv.copyMakeBorder(img,addLine,addLine,addLine,addLine,borderType=cv.BORDER_REPLICATE)
    
    #定位未扩充之前图像左上角元素在新图像中的下标索引,这个索引将用来遍历原图像的每一个像素点,相当于指针
    source_x = addLine#定义起始位置,即未扩充之前图像左上角元素在新图像中的下标索引
    source_y = addLine#定义起始位置,即未扩充之前图像左上角元素在新图像中的下标索引
    #addLine的值是单边添加边界的大小(行数,也是列数),一共四个边添加边界
    
    #在添加了边界后的图像中遍历未添加边界时的原像素点,进行滤波
    #外层控制行,内层控制列
    for delta_x in range(0,row):
        for delta_y in range(0,col):
            img[source_x,source_y] = np.sum(img[source_x-addLine:source_x+addLine+1,source_y-addLine:source_y+addLine+1]*kernel)
            source_y = source_y+1
        source_x = source_x+1#行加1,准备进行下行的所有列的遍历
        source_y = addLine#把列归位到原始的列起点准备下轮列遍历
    #经过上面的循环后,图像已经滤波完成了
    
    #剥除四边添加的边界,然后返回滤波后的图片
    return img[addLine:row+addLine,addLine:col+addLine]


#-----------------------------------------------------------------------------------------------------#
    
img = cv.imread("D:\\OpenCV\\testimg\\lena.png",cv.IMREAD_UNCHANGED)#图像读入后是BGR形式
imgGray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)#BGR图像转为灰度图像
imgGrayWithNosie = makeNoise(imgGray,3,0)
imgfilted = guassianImgFilt(imgGrayWithNosie,5,0)
cv.imshow("origin",img)
cv.imshow("gray",imgGray)
cv.imshow("GrayWithNosie",imgGrayWithNosie)
cv.imshow("filted",imgfilted)
cv.waitKey()
cv.destroyAllWindows()

如果对于卷积和卷积核不太理解的话可以参考我以前的一篇博客:
点击这里查看


声明:原本是在word中写的本篇博客,里面有mathtype敲出来的公式(CSDN不支持mathtype),转换为LaTex公式后放到博客里排版太乱了,所以就导出了PDF,分页输出图片,把图片放到博客里,这样排版效果更好一些。如果觉得大小不太合适可以按住CTRL键滑动鼠标滑轮缩放。本博客所用代码附在最后

你可能感兴趣的:(图像处理,python,opencv)