暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

OpenCV-Python - 图像处理 - 基础 - 平滑图像

数据库杂货铺 2022-02-02
844

平滑图像

 

目标

 

在本文将学习如何使用OpenCV函数将各种线性过滤器应用于平滑图像,例如:

 

 blur()

 GaussianBlur()

 medianBlur()

 bilateralFilter()

 

理论

 

注意

 

下面的解释来自 Richard Szeliski 的《计算机视觉:算法和应用》一书和 LearningOpenCV

 

 平滑,也称为模糊,是一种简单且常用的图像处理操作。

 

 要进行平滑处理的原因有很多。本文将重点介绍用于减少噪声的平滑处理。

 

 为了执行平滑操作,我们将对图像应用滤波器。最常见的滤波器类型是线性的,其中输出像素的值(如 g(i,j))被确定为输入像素值(如 f(i+k,j+l))的加权和:

 


 

h(k,l) 称为核,它只不过是滤波器的系数。

 

它有助于将滤波器可视化为在图像上滑动的系数窗口。

 

 滤波器有很多种,这里我们将提到最常用的:

 

归一化盒子滤波器

 

 这个滤波器是最简单的!每个输出像素是其内核邻域的平均值(所有邻域的权重相等)

 

 内核如下:

 


 
高斯滤波器

 

 可能是最有用的滤波器(虽然不是最快的)。高斯滤波是通过将输入阵列中的每个点与高斯核卷积,然后将它们相加来生成输出阵列来完成的。

 

 为了让画面更清晰,请回顾一维高斯核是什么样子。

 

 

 

假设图像是1维,可以注意到位于中间的像素将具有最大的权重。邻域的权重随着它们与中心像素之间的空间距离的增加而减小。

 

注意

 

请记住,二维高斯分布可以表示为:

 

 


 

其中μ表示均值,σ2表示方差(基于每个变量xy

 

中值滤波器

 

中值滤波器遍历信号(在本例中为图像)的每个元素,并将每个像素替换为其相邻像素的中值(相邻像素位于被评估像素周围的正方形邻域中)。

 

双边滤波器

 

 到目前为止,我们已经解释了一些主要目标是平滑输入图像的过滤器。然而,有时滤波器不仅能消除噪声,还能平滑边缘。为了避免这种情况(至少在一定程度上),我们可以使用双边滤波器。

 

 与高斯滤波器类似,双边滤波器也会考虑相邻像素,会为每个像素分配权重。这些权重有两个部分,第一部分与高斯滤波器使用的加权方式相同。第二部分考虑相邻像素和被评估像素之间的强度差异。

 

代码

 

此程序做了什么?

 

 加载图像

 

 应用4种不同类型的滤波器(理论部分提到的),并按顺序显示过滤后的图像

 

 

import sys
import cv2 as cv
import numpy as np
# 全局变量
DELAY_CAPTION = 1500
DELAY_BLUR = 100
MAX_KERNEL_LENGTH = 31
src = None
dst = None
window_name = 'Smoothing Demo'


def main(argv):
cv.namedWindow(window_name, cv.WINDOW_AUTOSIZE)
# 加载源图像
imageName = argv[0] if len(argv) > 0 else 'horizontal.png'
global src
src = cv.imread(imageName)
if src is None:
print ('打开图片发生错误')
print ('用法: smoothing.py [图片名称 -- 默认 horizontal.png] \n')
return -1

if display_caption('Original Image') != 0:
return 0

global dst
dst = np.copy(src)
if display_dst(DELAY_CAPTION) != 0:
return 0

# Applying Homogeneous blur
if display_caption('Homogeneous Blur') != 0:
return 0

for i in range(1, MAX_KERNEL_LENGTH, 2):
dst = cv.blur(src, (i, i))
if display_dst(DELAY_BLUR) != 0:
return 0

# Applying Gaussian blur
if display_caption('Gaussian Blur') != 0:
return 0

for i in range(1, MAX_KERNEL_LENGTH, 2):
dst = cv.GaussianBlur(src, (i, i), 0)
if display_dst(DELAY_BLUR) != 0:
return 0

# Applying Median blur
if display_caption('Median Blur') != 0:
return 0

for i in range(1, MAX_KERNEL_LENGTH, 2):
dst = cv.medianBlur(src, i)
if display_dst(DELAY_BLUR) != 0:
return 0

# Applying Bilateral Filter
if display_caption('Bilateral Blur') != 0:
return 0

for i in range(1, MAX_KERNEL_LENGTH, 2):
dst = cv.bilateralFilter(src, i, i * 2, i / 2)
if display_dst(DELAY_BLUR) != 0:
return 0

# Done
display_caption('Done!')
return 0


def display_caption(caption):
global dst
dst = np.zeros(src.shape, src.dtype)
rows, cols, _ch = src.shape
cv.putText(dst, caption,
(int(cols / 4), int(rows / 2)),
cv.FONT_HERSHEY_COMPLEX, 1, (255, 255, 255))
return display_dst(DELAY_CAPTION)


def display_dst(delay):
cv.imshow(window_name, dst)
c = cv.waitKey(delay)
if c >= 0 : return -1
return 0


if __name__ == "__main__":
main(sys.argv[1:])

 

代码介绍

 

下面仅介绍图像平滑过程用到的 OpenCV 函数。

 

归一化盒子滤波器

 

对于此过滤器,OpenCV 提供了函数 blur() 来执行平滑。指定了 4 个参数(针对C++版函数):

 

 src: 源图像

 

 dst: 目标图像

 

 Size( w, h ): 定义要使用的内核的大小(宽度为w像素,高度为h像素)

 

 Point(-1, -1): 指示锚定点(评估的像素)相对于邻域的位置。如果存在负值,则内核的中心被视为锚定点。

 

for i in range(1, MAX_KERNEL_LENGTH, 2):
dst = cv.blur(src, (i, i))
if display_dst(DELAY_BLUR) != 0:
return 0

 

高斯滤波器:

 

通过函数 GaussianBlur() 执行:这里我们介绍以下参数(针对C++版本函数):

 

 src: 源图像

 

 dst: 目标图像

 

 Size(w, h): 要使用的内核的大小(要考虑的邻域)。w  h 必须是奇数和正数,否则大小将使用 σx 和 σy 参数计算。

 

 σx: x 的标准差。0 意味着 σx 是用核大小计算的。

 

 σy: y 的标准差。0 意味着 σy 是用核大小计算的。

 

for i in range(1, MAX_KERNEL_LENGTH, 2):
dst = cv.GaussianBlur(src, (i, i), 0)
if display_dst(DELAY_BLUR) != 0:
return 0

 

中值滤波器:

 

这个滤波器由 medianBlur() 函数实现,使用以下参数:

 

 src: 源图像

 

 dst: 目标图像,必须与 src 类型相同

 

 i: 内核的大小(只有一个,因为使用方窗)。必须是奇数。

 

for i in range(1, MAX_KERNEL_LENGTH, 2):
dst = cv.medianBlur(src, i)
if display_dst(DELAY_BLUR) != 0:
return 0

 

双边滤波器

 

OpenCV 函数 bilateralFilter() 提供,我们使用5个参数(针对C++版本):

 

 src:源图像

 

 dst:图像

 

 d:每个像素邻域的直径。

 

 σColor:颜色空间中的标准偏差。

 

 σSpace:坐标空间中的标准偏差(以像素为单位)

# 记住,双边滤波有点慢,所以随着数值增大,它需要很长时间
for i in range(1, MAX_KERNEL_LENGTH, 2):
dst = cv.bilateralFilter(src, i, i * 2, i / 2)
if display_dst(DELAY_BLUR) != 0:
return 0

  

 

 

 

官方文档:

https://docs.opencv.org/4.5.5/dc/dd3/tutorial_gausian_median_blur_bilateral_filter.html

文章转载自数据库杂货铺,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论