Python-OpenCV——Image Blurring(Image Smoothing)

通过将图像与低通滤波器内核卷积来实现图像模糊。它有助于消除噪音。它实际上从图像中去除了高频内容(例如:噪声,边缘)。因此在此操作中边缘会有点模(嗯,有模糊技术,也不会模糊边缘)。 OpenCV主要提供四种模糊技术。

需要注意的是,图像模糊也叫图像平滑,它有助于降低噪声,但有噪声与模糊并不是等同的。

均值模糊

这是通过将图像与标准化的盒式过滤器( normalized box filter)进行卷积来完成的。它只取内核区域下所有像素的平均值并替换中心元素。这是由函数cv2.blur()或cv2.boxFilter()完成的。查看文档以获取有关内核的更多详细信息。我们应该指定内核的宽度和高度。 3x3标准化的盒式过滤器如下所示:

$$K = frac{1}{9} egin{bmatrix} 1 & 1 & 1 \ 1 & 1 & 1 \ 1 & 1 & 1 end{bmatrix}$$

 Note: 如果您不想使用规范化的框过滤器,请使用cv2.boxFilter()。将参数normalize = False传递给函数。 

      使用5x5大小的内核检查下面的示例演示:

import cv2
import numpy as np

img = cv2.imread("./Pictures/girl.png")

blur2 = cv2.blur(img, (5,5))


htich = np.hstack((img,blur2))
cv2.imwrite("./Pictures/mreger_img.png", htich)
cv2.imshow("merged_img", htich)
cv2.waitKey(0)
cv2.destroyAllWindows()

效果:

中值模糊(中值滤波)

这里,函数cv2.medianBlur()取内核区域下所有像素的中值,并用该中值替换中心元素。这对图像中的椒盐噪声非常有效。有趣的是,在上述滤波器中,中心元素是新计算的值,其可以是图像中的像素值或新值。但在中值模糊中,中心元素总是被图像中的某个像素值所取代。它有效地降低了噪音。其内核大小应为正奇数

     例如,自己手动添加的椒盐噪声、模拟实现的中值滤波、库中的中值滤波。

import cv2
import numpy as np


def saltpepper(img,rate):
    m=int((img.shape[0]*img.shape[1])*rate)
    for a in range(m):
        i=int(np.random.random()*img.shape[1])
        j=int(np.random.random()*img.shape[0])
        if img.ndim==2:
            img[j,i]=255
        elif img.ndim==3:
            img[j,i,0]=255
            img[j,i,1]=255
            img[j,i,2]=255
    for b in range(m):
        i=int(np.random.random()*img.shape[1])
        j=int(np.random.random()*img.shape[0])
        if img.ndim==2:
            img[j,i]=0
        elif img.ndim==3:
            img[j,i,0]=0
            img[j,i,1]=0
            img[j,i,2]=0
    return img

def My_medianBlur(img, kernal):
    l = int((kernal-1) / 2)
    ret = img.copy()
    for i in range(0, img.shape[0]):
        for j in range(0, img.shape[1]):
            x_s = y_s = -l
            x_t = y_t = l
            if i <= l:
                x_s = i
            if j <= l:
                y_s = j
            if i >= img.shape[0] - l - 1:
                x_t =  img.shape[0] - i - 1
            if j >= img.shape[1] - l - 1:
                y_t =  img.shape[1] - j - 1
            part=[]
            for k1 in range(x_s, x_t + 1):
                for k2 in range(y_s, y_t + 1):
                    part.append(img[i + k1][j + k2])
            part.sort()           #排序以找到中间值
            length = len(part)
            mid = int(length / 2)
            ret[i][j] = part[mid]
    return ret

raw_img = cv2.imread('./Pictures/1.jpg', cv2.IMREAD_GRAYSCALE)


img = raw_img.copy()
sp_img = saltpepper(img,0.02)    #添加椒盐噪声,会改变原图像


img1 = My_medianBlur(sp_img, 5)
img2 = cv2.medianBlur(sp_img, 5)

htich1 = np.hstack((raw_img, sp_img))
htich2 = np.hstack((img1, img2))
vtich = np.vstack((htich1, htich2))    #对比显示,左上为原图,右上为添加椒盐噪声,左下为自实现中值滤波,右下为库中的中值滤波

cv2.imshow('median_img',vtich)
cv2.waitKey(0)
cv2.destroyAllWindows()  
                
        

效果:

高斯模糊

      在此,使用高斯核代替箱式滤波器。它是通过函数cv2.GaussianBlur()完成的。我们应该指定内核的宽度和高度,它应该是正数和奇数。我们还应分别指定X和Y方向的标准偏差,sigmaX和sigmaY。如果仅指定了sigmaX,则sigmaY与sigmaX相同。如果两者都为零,则根据内核大小计算它们。高斯模糊在从图像中去除高斯噪声方面非常有效。

      与均值模糊相比,只是把卷积模板中的值换一下,不是全1了,换成一组符合高斯分布的数值放在模板里面,比如这时中间的数值最大,往两边走越来越小,构造一个小的高斯包。

      如果需要,可以使用函数cv2.getGaussianKernel()创建高斯内核。

函数原型:

dst = cv.GaussianBlur(src, ksize, sigmaX[, dst[, sigmaY[, borderType=BORDER_DEFAULT]]] 
参数 描述
SRC 输入图像
DST 输出图像
ksize 高斯内核大小。[高度宽度]。高度和宽度应该是奇数,并且可以具有不同的值。如果ksize设置为[0 0],则从sigma值计算ksize。
sigmaX 沿X轴(水平方向)的内核标准偏差。
sigmaY 沿Y轴(垂直方向)的内核标准偏差。如果sigmaY = 0,则sigmaX取sigmaX值
borderType 在图像边界上应用内核时指定图像边界。可能的值有:cv.BORDER_CONSTANT cv.BORDER_REPLICATE cv.BORDER_REFLECT cv.BORDER_WRAP cv.BORDER_REFLECT_101 cv.BORDER_TRANSPARENT cv.BORDER_REFLECT101 cv.BORDER_DEFAULT cv.BORDER_ISOLATED

(其实上面两种也有同样的参数)

上面的代码可以修改为高斯模糊:

blur2 = cv2.GaussianBlur(img,(5,5),cv2.BORDER_DEFAULT)

效果:

双边滤波

      cv2.bilateralFilter()在降低噪音方面非常有效,同时保持边缘清晰。但与其他过滤器相比,操作速度较慢。我们已经看到高斯滤波器采用像素周围的邻域并找到其高斯加权平均值。该高斯滤波器仅是空间的函数,即,在滤波时考虑附近的像素。它没有考虑像素是否具有几乎相同的强度。它不考虑像素是否是边缘像素。所以它也模糊了边缘,我们不想这样做。

      双边滤波器在空间中也采用高斯滤波器,但还有一个高斯滤波器,它是像素差的函数。空间的高斯函数确保仅考虑附近的像素用于模糊,而强度差的高斯函数确保仅具有与中心像素相似强度的那些像素被认为是模糊的。因此它保留了边缘,因为边缘处的像素将具有较大的强度变化。

      具体的,图像中每个像素处的强度值被来自附近像素的强度值的加权平均值替换。该权重可以基于高斯分布。至关重要的是,权重不仅取决于欧几里德像素距离,还取决于辐射度差异。例如,范围差异,例如颜色强度,深度距离等。这通过系统地循环每个像素并相应地调整相邻像素的权重来保留锐边。

参数 描述
src 原图片
dst 目标图片,形状与原图片相同
d 过滤期间使用的每个像素邻域的直径。如果它是负数,则从sigmaSpace计算。
sigmaColor 在颜色空间进行过滤,参数的值越大意味着像素邻域内的更远的颜色(参见sigmaSpace)将混合在一起,从而产生更大的半等颜色区域。
sigmaSpace 在坐标空间进行过滤,较大的参数值意味着只要它们的颜色足够接近,更远的像素就会相互影响(参见sigmaColor)。当d> 0时,无论sigmaSpace如何,它都指定邻域大小。否则,d与sigmaSpace成比例。

将上面的代码修改为双边滤波,与高斯模糊进行对比:

blur3 = cv2.bilateralFilter(img,20,75,75)

效果:

可见,保留了线条,但脸部明显已被模糊。

2D卷积

与一维信号一样,图像也可以使用各种低通滤波器(LPF),高通滤波器(HPF)等进行滤波.LPF有助于消除噪声,模糊图像等.HPF滤波器有助于查找边缘图片。

OpenCV提供了一个函数cv2.filter2D()来将自定义内核与图像进行卷积。

例如,为了简便仍使用平均值,我们将尝试对图像进行平均滤波。 5x5平均滤波器内核如下所示:

$$K = frac{1}{25} egin{bmatrix} 1 & 1 & 1 & 1 & 1 \ 1 & 1 & 1 & 1 & 1 \ 1 & 1 & 1 & 1 & 1 \ 1 & 1 & 1 & 1 & 1 \ 1 & 1 & 1 & 1 & 1 end{bmatrix}$$

操作是这样的:将此内核保持在像素上方,添加该内核下方的所有25个像素,取其平均值并用新的平均值替换中心像素。它继续对图像中的所有像素执行此操作。试试这段代码并检查结果:

import cv2
import numpy as np

img = cv2.imread("./Pictures/girl.png")

blur2 = cv2.blur(img,(5,5),cv2.BORDER_DEFAULT)

kernel = np.ones((5,5),np.float32)/25
blur3 = cv2.filter2D(img,-1,kernel)

htich = np.hstack((img,blur2,blur3))
cv2.imwrite("./Pictures/mreger_img.png", htich)
cv2.imshow("merged_img", htich)
cv2.waitKey(0)
cv2.destroyAllWindows()

效果:

参考链接:

1、高斯模糊https://www.tutorialkart.com/opencv/python/opencv-python-gaussian-image-smoothing/

2、双边滤波http://opencvexamples.blogspot.com/2013/10/applying-bilateral-filter.html

3、官方文档https://docs.opencv.org/3.1.0/d4/d13/tutorial_py_filtering.html

4、cv2.filter2D示例https://www.programcreek.com/python/example/89373/cv2.filter2D

原文地址:https://www.cnblogs.com/lfri/p/10596669.html