凡科建设网站别人能进去么,一级消防工程师考试通过率,机械行业网站建设制作开发方案,手工活外包加工网OpenCV与图像处理学习五——图像滤波与增强#xff1a;线性、非线性滤波、直方图均衡化与Gamma变换三、图像滤波与增强3.1 线性滤波3.1.1 方框滤波3.1.2 均值滤波3.1.3 高斯滤波3.1.4 一般卷积滤波3.2 非线性滤波3.2.1 中值滤波3.2.2 双边滤波3.3 图像直方图均衡化3.3.1 单通道…
OpenCV与图像处理学习五——图像滤波与增强线性、非线性滤波、直方图均衡化与Gamma变换三、图像滤波与增强3.1 线性滤波3.1.1 方框滤波3.1.2 均值滤波3.1.3 高斯滤波3.1.4 一般卷积滤波3.2 非线性滤波3.2.1 中值滤波3.2.2 双边滤波3.3 图像直方图均衡化3.3.1 单通道图像全局均衡化3.3.2 三通道图像全局均衡化3.3.3 局部均衡化/对比度限制自适应直方图均衡化CLAHE3.4 Gamma变换上两次的笔记地址 OpenCV与图像处理学习三——图像基本操作1 OpenCV与图像处理学习四——图像基本操作2
这次笔记的主要内容为图像滤波与增强。
对应的OpenCV官方python文档为
三、图像滤波与增强
所谓滤波实际上是信号处理领域的一个概念就是将信号中特定频率分量滤除的一项操作。而图像又可以看成是一个二维信号其中像素值代表信号的强弱。
而图像的高低频的定义如下所示
高频图像上变化剧烈的部分低频图像灰度值变化缓慢平坦的地方。
根据图像的高低频设置高通和低通滤波器可以对图像进行相应的变化其中高通滤波器可以检测变化尖锐明显的地方低通滤波器可以让图像变得平滑消除噪声。
所以总的来说图像滤波的作用高通滤波器用于边缘检测边缘是像素值变化剧烈的地方低通滤波器用于图像的平滑去噪。
下面会介绍几种滤波的方法在此之前还要先了解一个概念领域算子如下图所示利用给定像素周围的像素值决定此像素的最终输出值的一种算子。其实就是后来的卷积操作 线性滤波就是一种常用的领域算子像素的输出取决于输入像素的加权和 那么非线性滤波自然就不遵循这个规则。
此外还将介绍可以改善图像视觉效果的技术——直方图均衡化与Gamma变换。
3.1 线性滤波
3.1.1 方框滤波
方框滤波被封装在一个名为boxFilter的函数中即boxFilter函数的作用是使用方框滤波器box filter来模糊一张图片从src输入从dst输出它是用如下的滤波核领域算子来计算的 函数
dst cv2.boxFilter( src, ddepth, ksize[, dst[, anchor[, normalize[, borderType]]]] )参数如下所示
src输入图像。dst输出图像与src同尺寸和类型。ddepth目标图像深度-1表示使用src的图像深度。ksize滤波核的尺寸一般为奇数。anchor锚点位置默认为滤波核的中心位置。normalize表示滤波核是否需要标准化为True的话就等于均值滤波的滤波核为False的话很可能卷积计算的结果会超出 0-255 这个范围。
下面来看个例子
import cv2
import numpy as np
img cv2.imread(girl2.png, cv2.IMREAD_UNCHANGED)
r cv2.boxFilter(img, -1, (7,7), normalize 1)
d cv2.boxFilter(img, -1, (3,3), normalize 0)
cv2.namedWindow(img, cv2.WINDOW_AUTOSIZE)
cv2.namedWindow(r, cv2.WINDOW_AUTOSIZE)
cv2.namedWindow(d, cv2.WINDOW_AUTOSIZE)
cv2.imshow(img, img)
cv2.imshow(r, r)
cv2.imshow(d, d)
cv2.waitKey(0)
cv2.destroyAllWindows()输出结果如下图所示 可见如果将normalize参数设置为False图像计算出来的输出很可能导致值过大。
3.1.2 均值滤波
均值滤波是一种最简单的滤波处理它取得是卷积核区域内元素的均值用cv2.blur函数实现它的卷积核如下所示 举个3×3的例子 函数
dst cv2.blur( src, ksize[, dst[, anchor[, borderType]]] )参数和方框滤波很相似可以直接参考方框滤波的参数解释。官方文档特意强调了一句
The call blur(src, dst, ksize, anchor, borderType) is equivalent to boxFilter(src, dst, src.type(), anchor, true, borderType).
再次说明均值滤波是方框滤波的一个常用的特例。
下面看个例子
import cv2
import numpy as np
from matplotlib import pyplot as plt
img cv2.imread(image/opencv.png)
cv2.imshow(img, img)
cv2.waitKey(0)
cv2.destroyAllWindows()
img cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
blur cv2.blur(img, (3, 3))
plt.subplot(121), plt.imshow(img), plt.title(Original)
plt.subplot(122), plt.imshow(blur), plt.title(Blurred)
plt.xticks([]), plt.yticks([])
plt.show()输出结果为 均值滤波之后的结果是会变的比较模糊将核尺寸改为7,7输出结果为 所以均值滤波的核的尺寸越大滤波之后的图像越模糊。
3.1.3 高斯滤波
高斯滤波是一种线性平滑滤波适用于消除高斯噪声广泛应用于图像处理的减噪过程。高斯滤波的卷积核权重就不像前面两种滤波方法是一样的了它的中间像素点的权重最高越远离中心的像素权重越小其原理是一个二维高斯函数如下图所示 高斯滤波相比均值滤波效率要慢但是可以有效消除高斯噪声能保留更多的图像细节所以被称为最有用的滤波器。
函数
dst cv2.GaussianBlur( src, ksize, sigmaX[, dst[, sigmaY[, borderType]]] )参数如下所示
src输入图像。ksize高斯核的尺寸核的高度和宽度可以不等但是必须是正的奇数也可以是0那就通过sigma参数计算得到。sigmaXX方向上高斯分布的标准差调整sigma其实是在调整周围像素对当前像素的影响程度调大sigma即提高了远处像素对中心像素的影响程度滤波结果也就越平滑。sigmaYY方向上高斯分布的标准差。
看个例子
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
img cv.imread(image/median.png)
img cv.cvtColor(img, cv.COLOR_BGR2RGB)
blur cv.GaussianBlur(img, (7, 7), 7)
plt.subplot(121), plt.imshow(img), plt.title(Original)
plt.xticks([]), plt.yticks([])
plt.subplot(122), plt.imshow(blur), plt.title(Blurred)
plt.xticks([]), plt.yticks([])
plt.show()结果如下所示 可见高斯滤波是一种很好的去除噪声的滤波方法。
3.1.4 一般卷积滤波
上面三种是比较特殊的滤波方法其卷积核内的权重有规定的要求而一般的卷积滤波的卷积核理论上可以是任意值经过适当的选择和设置可以完成一些特殊的操作。它的像素值计算公式如下所示
它所用到的函数是cv2.filter2D()函数如下
dst cv2.filter2D( src, ddepth, kernel[, dst[, anchor[, delta[, borderType]]]] )参数如下所示
src输入图像。ddepth图像深度。kernel卷积核。anchor锚点位置默认为中心位置。delta可选项在计算得到的值的基础上加上的值。
看两个例子一个是用它来做均值滤波一个是做特殊的操作——锐化它们的差别就是所使用的卷积核不一样
均值滤波
import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
img cv.imread(./image/opencv.png)
kernel np.ones((5, 5), np.float32)/25
dst cv.filter2D(img, -1, kernel)
plt.subplot(121), plt.imshow(img), plt.title(Original)
plt.xticks([]), plt.yticks([])
plt.subplot(122), plt.imshow(dst), plt.title(Averaging)
plt.xticks([]), plt.yticks([])
plt.show()锐化
import cv2 as cv
import numpy as npdef custom_blur_demo(image):kernel np.array([[0, -1, 0], [-1, 5, -1], [0, -1, 0]], np.float32) # 锐化dst cv.filter2D(image, -1, kernelkernel)cv.imshow(custom_blur_demo, dst)src cv.imread(./image/sharpen.png)
cv.namedWindow(input image, cv.WINDOW_AUTOSIZE)
cv.imshow(input image, src)
custom_blur_demo(src)
cv.waitKey(0)
cv.destroyAllWindows()ps卷积核像上面那样设置就可以进行一定的锐化处理即图像看起来更清晰。
3.2 非线性滤波
非线性滤波不像线性滤波那样是一个和卷积核对应位相乘后相加的线性运算这里介绍中值滤波核双边滤波。
3.2.1 中值滤波
中值滤波是用像素点邻域灰度值的中值代替该点的灰度值中值滤波可以去除椒盐噪声和斑点噪声。
函数
dst cv2.medianBlur( src, ksize[, dst] )参数
src输入图像。ksize核的大小这里不再是卷积核而只是取中值的一个范围。
看个例子
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
img cv.imread(image/median.png)
median cv.medianBlur(img, 7)plt.subplot(121), plt.imshow(img), plt.title(Original)
plt.xticks([]), plt.yticks([])
plt.subplot(122), plt.imshow(median), plt.title(median)
plt.xticks([]), plt.yticks([])
plt.show()输出结果为
3.2.2 双边滤波
双边滤波是结合图像的空间邻近度和像素值相似度的一种折中处理同时考虑空间与信息和灰度相似性达到保边去噪的目的具有简单、非迭代和局部处理的特点。
双边滤波在去噪的同时能较好的保留边缘信息。但与其他滤波器相比速度较慢。高斯滤波器取像素周围的一个邻域并找到它的高斯加权平均值。这种高斯滤波器是空间的函数也就是说滤波时考虑了附近的像素但它不考虑像素是否具有几乎相同的强度。它不考虑像素是否是边缘像素。所以它也模糊了边缘这是不太好的。
双边滤波器在空间上也采用高斯滤波器但多了一个高斯滤波器它是像素差的函数。空间高斯函数只考虑相邻像素的模糊而灰度差的高斯函数则只考虑与中心像素亮度相近的像素进行模糊处理。所以它保留了边缘因为边缘的像素会有很大的强度变化。
函数
dst cv2.bilateralFilter( src, d, sigmaColor, sigmaSpace[, dst[, borderType]] )参数如下所示
src输入图像。d像素的邻域直径若为非正数则通过sigma计算得到。sigmaColor灰度相似性高斯函数标准差。sigmaSpace空间高斯函数标准差。
看个例子
import cv2
from matplotlib import pyplot as plt
img cv2.imread(image/bilateral.png)
img cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
blur cv2.bilateralFilter(img, -1, 15, 10)
plt.subplot(121), plt.imshow(img), plt.title(Original)
plt.xticks([]), plt.yticks([])
plt.subplot(122), plt.imshow(blur), plt.title(Blurred)
plt.xticks([]), plt.yticks([])
plt.show()输出结果如下图所示 边缘信息保留的还可以。
3.3 图像直方图均衡化
3.3.1 单通道图像全局均衡化
目的直方图均衡化是将原图像通过某种变换得到一幅灰度直方图为均匀分布的新图像的方法。
基本思想对在图像中像素个数多的灰度级进行展宽而对像素个数少的灰度级进行缩减。从而达到清晰图像增强对比度的目的。
考虑一个图像其像素值仅限于某些特定的值范围内。例如较亮的图像将所有像素限制为高值。但是一个好的图像会有来自图像所有区域的像素。所以你需要将这个直方图拉伸到两端如下图所示来自维基百科这就是直方图均衡化的作用简单地说。这通常会提高图像的对比度。更详细的解释可以参考官方文档的内容讲解https://docs.opencv.org/4.1.2/d5/daf/tutorial_py_histogram_equalization.html 横坐标为像素值纵坐标为该像素值对应的像素的个数
函数
dst cv2.equalizeHist( src[, dst] )参数
src输入的8bit单通道图像。
作用是均衡化一张灰度图的像素值。具体的实现步骤是
统计直方图中每个灰度值出现的次数计算累计归一化直方图重新计算像素点的像素值。 来看个例子
# 导入opencv
import cv2
# 直接读为灰度图像
img cv2.imread(./image/dark.png, 0)
cv2.imshow(dark, img)
cv2.waitKey(0)
# 调用cv2.equalizeHist函数进行直方图均衡化
img_equal cv2.equalizeHist(img)cv2.imshow(img_equal, img_equal)
cv2.waitKey(0)
cv2.destroyAllWindows()效果如下图所示 原图是一张整体偏暗的图片直方图均衡化之后对比度得到了提高变得更清晰明亮了一些如果原图是一张过亮的图片那么均衡化会让它更暗一些。
3.3.2 三通道图像全局均衡化
基本思想是先将三通道分离对三个通道分别进行全局均衡化然后将均衡化之后的结果再合并通道恢复成彩色图像下面看个例子
import cv2
import numpy as np
img cv2.imread(./image/dark1.jpg)
# print(img.shape)
cv2.imshow(src, img)
# 彩色图像均衡化,需要分解通道 对每一个通道均衡化
(b, g, r) cv2.split(img)
bH cv2.equalizeHist(b)
gH cv2.equalizeHist(g)
rH cv2.equalizeHist(r)
# 合并每一个通道
result cv2.merge((bH, gH, rH))
cv2.imshow(dst, result)
cv2.waitKey(0)
cv2.destroyAllWindows()输出结果如下所示右边少截了一点
3.3.3 局部均衡化/对比度限制自适应直方图均衡化CLAHE
我们刚刚看到的全局直方图均衡化考虑了图像的全局对比度。在许多情况下这不是一个好主意。例如下图显示了输入图像及其全局直方图均衡化后的结果 直方图均衡化后背景对比度确实有所改善。但是比较两幅图像中雕像的脸。由于亮度过高我们丢失了那里的大部分信息。这是因为它的直方图并不像我们在前面的例子中所看到的那样局限于一个特定的区域试着绘制输入图像的直方图你会得到更多的直觉。
为了解决这一问题可以采用自适应直方图均衡化方法。在这种情况下图像被分成称为“tiles”的小块OpenCV中tileSize默认为8x8。然后这些块中的每一块都像往常一样被直方图均衡化。所以在一个很小的区域内直方图会局限在一个很小的区域内除非有噪声。如果有噪音就会被放大。为了避免这种情况应用对比度限制。如果任何直方图单元高于指定的对比度限制OpenCV中默认为40则在应用直方图均衡化之前这些像素将被剪裁并均匀分布到其他单元。在均衡后为了去除瓷砖边缘的伪影采用双线性插值。
OpenCV中这种均衡化对应的函数为
retval cv2.createCLAHE( [, clipLimit[, tileGridSize]] )参数只有两个
clipLimit对比度限制的阈值tileGridSize局部直方图均衡化的网格尺寸输入图像将被分成这么大的矩形小块分别均衡化。
看一下实现的代码
import numpy as np
import cv2 as cv
img cv.imread(tsukuba_l.png, 0)
# create a CLAHE object (Arguments are optional).
clahe cv.createCLAHE(clipLimit2.0, tileGridSize(8,8))
cl1 clahe.apply(img)
cv.imwrite(clahe_2.jpg,cl1)参见下面的结果并将其与上面的结果进行比较尤其是雕像区域
增强图像中的有用信息它可以是一个失真的过程其目的是要改善图像的视觉效果针对给定图像的应用场合。
3.4 Gamma变换
Gamma变换是对输入图像灰度值进行的非线性操作使输出图像灰度值与输入图像灰度值呈指数关系 目的Gamma变换就是用来图像增强其提升了暗部细节通过非线性变换让图像从曝光强度的线性响应变得更接近人眼感受的响应即将漂白相机曝光或过暗曝光不足的图片进行矫正。
看一个例子
import cv2
import numpy as np
imgcv2.imread(./image/dark1.jpg)
def adjust_gamma(image, gamma1.0):invGamma 1.0/gammatable []for i in range(256):table.append(((i / 255.0) ** invGamma) * 255)table np.array(table).astype(uint8)print(table)return cv2.LUT(image, table)img_gamma adjust_gamma(img, 2.0)
print(img_gamma)
cv2.imshow(img,img)
cv2.imshow(img_gamma,img_gamma)cv2.waitKey(0)
cv2.destroyAllWindows()先构建一个gamma变换的表table即0-255变换后变为多少然后对图像上的每个像素进行一个查表操作原像素值查表得到变换后的像素值即cv2.LUT函数的作用返回的就是gamma变换之后的图像结果如下所示
[ 0 15 22 27 31 35 39 42 45 47 50 52 55 57 59 61 63 6567 69 71 73 74 76 78 79 81 82 84 85 87 88 90 91 93 9495 97 98 99 100 102 103 104 105 107 108 109 110 111 112 114 115 116117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134135 136 137 138 139 140 141 141 142 143 144 145 146 147 148 148 149 150151 152 153 153 154 155 156 157 158 158 159 160 161 162 162 163 164 165165 166 167 168 168 169 170 171 171 172 173 174 174 175 176 177 177 178179 179 180 181 182 182 183 184 184 185 186 186 187 188 188 189 190 190191 192 192 193 194 194 195 196 196 197 198 198 199 200 200 201 201 202203 203 204 205 205 206 206 207 208 208 209 210 210 211 211 212 213 213214 214 215 216 216 217 217 218 218 219 220 220 221 221 222 222 223 224224 225 225 226 226 227 228 228 229 229 230 230 231 231 232 233 233 234234 235 235 236 236 237 237 238 238 239 240 240 241 241 242 242 243 243244 244 245 245 246 246 247 247 248 248 249 249 250 250 251 251 252 252253 253 254 255]若将gamma参数改为小于1的数如0.8则结果为
[ 0 0 0 0 1 1 2 2 3 3 4 5 5 6 6 7 8 89 9 10 11 11 12 13 13 14 15 16 16 17 18 19 19 20 2122 22 23 24 25 25 26 27 28 29 29 30 31 32 33 34 34 3536 37 38 39 40 40 41 42 43 44 45 46 47 47 48 49 50 5152 53 54 55 56 57 58 58 59 60 61 62 63 64 65 66 67 6869 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 8687 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104105 106 107 108 109 110 111 113 114 115 116 117 118 119 120 121 122 123124 125 127 128 129 130 131 132 133 134 135 136 137 139 140 141 142 143144 145 146 147 149 150 151 152 153 154 155 157 158 159 160 161 162 163164 166 167 168 169 170 171 173 174 175 176 177 178 180 181 182 183 184185 187 188 189 190 191 192 194 195 196 197 198 200 201 202 203 204 206207 208 209 210 212 213 214 215 216 218 219 220 221 222 224 225 226 227229 230 231 232 233 235 236 237 238 240 241 242 243 245 246 247 248 250251 252 253 255]可以通过比较两个gamma变换的表看出区别前者是将值普遍变大所以图会变亮后者是普遍变小所以变暗。