[OpenCv]图像增强

时间:2024-03-01 09:32:55

目录

前言

一、灰度变化

二、直方图修整

1.直方图概念

2.直方图变化

3.直方图均衡化

二、图像平滑

1.卷积模板

2.均值滤波

3.高斯滤波

4.中值滤波

三、图像锐化

1.梯度算子

2.使用Laplacian算子进行锐化

3.使用Sobel算子进行锐化

四、代码总结

1.图片

2.代码


前言

图像增强的目的是改善图像的视觉效果或者是图像更适合于人或及其分析处理,通过图像增强可以减少图片噪声,提高目标与背景的对比度,也可以强调或一直图像中的某些细节。

一、灰度变化

灰度变化是再图像处理时一个非常重要的步骤,因为计算机往往对颜色不是那么敏感。cv2提供了灰度变化的函数:
 

import cv2
img = cv2.imread('pic.png')  # 读取图片
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)  # 灰度变化

二、直方图修整

1.直方图概念

灰度直方图是描述图像中像素灰度级别分布的一种统计工具,它显示了图像中每个灰度级别出现的频次或数量。灰度直方图通常以灰度级别(通常是 0 到 255)为横坐标,以像素的数量或频次为纵坐标,用来展示图像的整体亮度分布情况。

我们可以使用一下方式绘制直方图:

import cv2
from matplotlib import pyplot as plt

img = cv2.imread('pic1.png')  # 读取图片
# 获取直方图
hist = cv2.calcHist([img], [0], None, [256], [0, 256])
plt.plot(hist)  # 绘制
plt.show()

pic1.png:

绘制出的直方图:

当然,我们也可以使用ps查看,具体步骤如下:

1.导入图片,

2.将图片转化为灰度图(如果已经是灰度图则忽略)

3.调出曲线

点击右下角调整图层(长得跟相机一样的图标再往有一个的那个图标),并选择曲线

就可以看到直方图了

2.直方图变化

可以看到直方图上有一根曲线(当然,最开始时是直线),这根线就是输入与输出的对应关系,比如最开始时是y=x的直线,则对应输出的灰度与输入的灰度相等,如果是下边这样的曲线,则对应输出的y,都比x要大,图片暗的地方变亮,

反过来,如果曲线是下边这样,会使亮的地方变暗

当然,曲线也可以是这样,对应的图片如右图

3.直方图均衡化

直方图均衡化的基本思想是把原始图像的直方图变换为均匀分布的形式,从而增加图像灰度的动态范围,以达到增强图像对比度的效果。经过均衡化处理的图像,其灰度级出现的概率相同,此时图像的嫡最大,图像所包含的信息量最大。

直方图均衡化:设r为灰度变换前的归一化灰度级(0<r<1),T(r)为变换函数,s=T(r)为变换后的归一化灰度级(0<3<1),变换函数T(r)满足下列条件:
(1)在0<r<1区间内,T(r)单值单调增加;
(2)对于0<r<1,有0<T(r)<1。
第(1)个条件保证了变换后图像的灰度级从黑到白的次序不变。第(2)个条件保证了变换前后图像灰度范围一致。反变换r=T(s)也应满足类似的条件。
由概率论知识可知,如果已知随机变量 的概率密度函数为p,(r),而随机变量n是的函数,即n=T(5),n的概率密度为p,(s),则可由p,(r)求出p,(s)。因为s=T(r)是单调增加的,因而它的反函数r=T(s)也是单调增加函数。可以求得随机变量的分布函数为

F,(s)=P(n<s)=P(<r)= p,(x) dx (3-8)

直方图均衡化的结果是扩展了灰度的动态范围

下面使用cv2绘制均衡化前后的图片以及直方图:
 

import numpy as np
import cv2
from matplotlib import pyplot as plt

img = cv2.imread('pic1.png')  # 读取图片
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)  # 灰度变化

# 直方图均衡化
img_eq = cv2.equalizeHist(img_gray)

# 直方图
hist1 = cv2.calcHist([img], [0], None, [256], [0, 255])
hist2 = cv2.calcHist([img_eq], [0], None, [256], [0, 255])

# 绘制直方图
fig, axs = plt.subplots(1, 2)

axs[0].plot(hist1)
axs[0].set_title('原始图像的直方图', fontproperties='SimSun')
axs[0].set_xlim([0, 256])

axs[1].plot(hist2)
axs[1].set_title('均衡化之后的图像的直方图', fontproperties='SimSun')
axs[1].set_xlim([0, 256])

plt.show()

# 使用np.concatenate将原始图像和均衡化之后的图像连接起来一起绘制
cv2.imshow('equalized image', np.concatenate((img_gray, img_eq), axis=1))
cv2.waitKey(0)

结果如下:

二、图像平滑

图像平滑的主要目的是消除噪声或模糊图像,去除小的细节或弥合目标间的缝隙。从信号频谱角度来看,信号缓慢变化的部分在频率域表现为低频,而迅速变化的部分表现为高频。如图像的边缘、跳跃以及噪声等灰度变化剧烈的部分代表图像的高频分量,而灰度变化缓慢的区域代表图像的低频分量。因此,可以在空间域或频率域通过低通滤波来减弱或消除高频分了而不影响低频分量以实现图像平滑。

1.卷积模板

模板操作是数字图像处理中常用的一种邻域运算方式,主要有卷积和相关两种,可以实现图像平滑、图像锐化、边缘检测等功能,模板常用矩阵表示,可以是一V 幅图像、一个滤波器或一个窗口,定义了参与运算的中心元素和邻域元素的相对位置及相关系数。模板的中心元素(或称原点)表示将要处理的元素,一般取模板中心点,也可根据
需要选取非中心点。
模板卷积(或相关)是指模板与图像进行卷积(或相关)运算,是一种线性滤波,其输出像素是输入邻城像素的线性加权和。模板卷积和相关分别定义为

g=f*h=>g(i,j)=\sum_{k}^{}\sum_{l}^{}f(i-k,j-l)h(k,l)

=\sum_{k}^{}\sum_{l}^{}f(k,l)h(i-k,j-l)

g=f\otimes h=>g(i,j)=\sum_{k}^{}\sum_{l}^{}f(i+k,j+l)h(k,l)

=\sum_{k}^{}\sum_{l}^{}f(k,l)h(i+k,j+l)

式中:为输入图像;h为模板;g为输出图像。
卷积与相关运算的主要区别在于卷积运算前需要将模板绕模板中心旋转180°,因其余运算过程一致而统称为模板卷积。模板卷积中的模板又称为卷积核,其元素称为卷积系数、模板系数或加权系数,其大小及排列顺序决定了对图像进行邻域处理的类型。模板卷积可以看作是对邻域像素进行加权求和的过程,基本步骤如下:
(1)模板在输入图像上移动,让模板原点与某个输入像素f(i,j)重合;
(2)模板系数与模板下对应的输入像素相乘,再将乘积相加求和;
(3)将第(2)步的运算结果赋予与模板原点对应像素的输出g(i,j)。
下图是一个模板卷积示例,模板原点在模板中心。当模板原点移至输入图像的圆圈处时,卷积核与被其覆盖的区域中的内部虚线矩形框做点积,即0×5+(-1)×5+0×8+(-1)×5+0×1+1×7+0×5+1×6+0×8=3,将此结果赋予输出图像的对应像素(如图3-12(c)的圆圈处)。模板在输入图像中逐像素移动并进行类似运算,即可得模板卷积结果(如图3-12(c)所示)。

5 5 5 5 8 8 8
5 5 5 5 8 8 8
5 5 5 5 8 8 8
5 5 5 1 7 8 8
5 5 5 6 8 8 8
3 3 8 8 8 8 8
3 3 8 8 8 8 8

输入图像

0 -1 0
-1 0 1
0 1 0

卷积核
 

0 0 3 3 0
0 0 -1 2 0
0 -4 3 7 1
-2 4 10 3 0
3 8 2 0 0

模板卷积结果

2.均值滤波

顾名思义,均值滤波就是将卷积核内的值求平均,

\frac{1}{9}*\begin{bmatrix} 1 &1 &1 \\ 1& 1 &1 \\ 1& 1 &1 \end{bmatrix}

这样可以去除突变的噪声点,对于处理高斯噪声十分有效,代码实现如下:

import cv2
from matplotlib import pyplot as plt

img = cv2.imread('pic.png')
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# 均值滤波,卷积核(3,3)
img_out1 = cv2.blur(img, ksize=(3, 3))

fig, axs = plt.subplots(1, 2)

axs[0].imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
axs[0].set_title('原始图像', fontproperties='SimSun'), axs[0].set_xticks([])
axs[1].imshow(cv2.cvtColor(img_out1, cv2.COLOR_BGR2RGB))
axs[1].set_title('均值滤波', fontproperties='SimSun'), axs[1].set_xticks([])
plt.show()

放大一些看一下细节:

均值滤波在去除噪点的同时会使图片变得模糊

3.高斯滤波

与均值滤波类似,只是权重不同,它可以使得离得进的像素该像素点影响大一些,离得远的对该像素点的影响小一些。代码实现如下:

import cv2
from matplotlib import pyplot as plt

img = cv2.imread('pic.png')
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# 高斯滤波
img_out1 = cv2.GaussianBlur(img, ksize=(5, 5), sigmaX=0, sigmaY=0)

fig, axs = plt.subplots(1, 2)

axs[0].imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
axs[0].set_title('原始图像', fontproperties='SimSun'), axs[0].set_xticks([])
axs[1].imshow(cv2.cvtColor(img_out1, cv2.COLOR_BGR2RGB))
axs[1].set_title('高斯滤波', fontproperties='SimSun'), axs[1].set_xticks([])
plt.show()

4.中值滤波

同样很好理解,该像素点的值改为卷积核内所有像素从高到低排序后的中值即可。

代码如下:
 

import cv2
from matplotlib import pyplot as plt

img = cv2.imread('pic.png')
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# 中值滤波
img_out1 = cv2.medianBlur(img, 5)

fig, axs = plt.subplots(1, 2)

axs[0].imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
axs[0].set_title('原始图像', fontproperties='SimSun'), axs[0].set_xticks([])
axs[1].imshow(cv2.cvtColor(img_out1, cv2.COLOR_BGR2RGB))
axs[1].set_title('中值滤波', fontproperties='SimSun'), axs[1].set_xticks([])
plt.show()

中值滤波能够有效消除椒盐噪音,高斯滤波则能有效消除高斯噪声,对椒盐噪声的效果就没那么明显了。

三、图像锐化

第二章对图像进行平滑之后,会使得图像变的模糊。图像锐化的目的是使模糊的图像变清晰,增强图像的边缘等细节。图像锐化增强边缘的同时会增强噪声,因此一般先去除或减轻噪声,再进行锐化处理。图像锐化可以在空间域或频率域通过高通滤波来实现,即减弱或消除低频分量而不影响高频分量。空间域高通滤波主要用模板卷积来实现。

1.梯度算子

常用的梯度算子见表,他们分别对应Gx和Gy。

常用的梯度算子
算子名称 模板H1 模板H2 特点
Roberts \begin{bmatrix} 0* &-1 \\ 1&0 \end{bmatrix} \begin{bmatrix} -1* &0 \\ 0&1 \end{bmatrix} 各向同性,对噪声敏感;模板储存为偶数,中心位置不明显
Prewitt \begin{bmatrix} -1 &0 &1 \\ -1&0* &1 \\ -1& 0 & 1 \end{bmatrix} \begin{bmatrix} -1 &-1 &-1 \\ 0&0* &0 \\ 1& 1 & 1 \end{bmatrix} 引入了平均因素,对噪声有抑制作用,操作简单
Sobel \begin{bmatrix} -1 &0 &1 \\ -2&0* &2 \\ -1& 0 & 1 \end{bmatrix} \begin{bmatrix} -1 &-2 &-1 \\ 0&0* &0 \\ 1& 2 & 1 \end{bmatrix} 引入了平均因素,增强了最近像素的影响,噪声抑制效果比Prewitt要好
Krisch \begin{bmatrix} -3 &-3 &5 \\ -3&0* &5 \\ -3& -3 & 5 \end{bmatrix} \begin{bmatrix} -3 &-3 &-3 \\ -3&0* &5 \\ 5& 5 & 5\end{bmatrix} 噪声抑制作用较好;需求出8个方向的响应(这里只给出两个方向的模板)
Isotropic Sobel \begin{bmatrix} -1 &0 &1 \\ -\sqrt{2}&0* &\sqrt{2} \\ -1& 0 & 1 \end{bmatrix} \begin{bmatrix} -1 &-\sqrt{2} &-1 \\ 0&0* &0 \\ 1& \sqrt{2} & 1 \end{bmatrix} 权值反比于邻点与中心点的距离,检测沿不同方向边缘时梯度幅度一致,即具有各向同性

2.使用Laplacian算子进行锐化

与前边的代码都类似,就不过多介绍了

import cv2
import numpy as np

# 读取图像
img = cv2.imread('pic1.png', cv2.IMREAD_GRAYSCALE)

img_med = cv2.medianBlur(img, 5)


# 使用拉普拉斯算子进行图像锐化
laplacian = cv2.Laplacian(img_med, cv2.CV_64F)
sharp_img = img_med + laplacian

# 将结果限制在 0-255 范围内
sharp_img = np.clip(sharp_img, 0, 255).astype(np.uint8)

# 显示原始图像和锐化后的图像
cv2.imshow('Original Image', img)
cv2.imshow('laplacian Image', sharp_img)
cv2.waitKey(0)
cv2.destroyAllWindows()

3.使用Sobel算子进行锐化

import cv2
import numpy as np

# 读取图像
img = cv2.imread('pic1.png', cv2.IMREAD_GRAYSCALE)

img_med = cv2.medianBlur(img, 5)

# 使用Sobel算子
Soble = cv2.Sobel(img_med, cv2.CV_8U, 1, 0, ksize=3)
Soble = np.uint8(np.absolute(Soble))  # 将Sobel结果转换为 uint8 类型

Soble_img = cv2.addWeighted(img_med, 1, Soble, 1, 0)

# 将结果限制在 0-255 范围内
Soble_img = np.clip(Soble_img, 0, 255).astype(np.uint8)
# 显示原始图像和锐化后的图像
cv2.imshow('Original Image', img)
cv2.imshow('Soble_img Image', Soble_img)

cv2.waitKey(0)
cv2.destroyAllWindows()

四、代码总结

1.图片

pic.png

pic1.png(pic.png变为灰度图)

pic2.png(pic.png中值滤波)

2.代码

test1:

import cv2
import matplotlib.pyplot as plt

img = cv2.imread('pic.png')

# 均值滤波,卷积核(3,3)
img_out1 = cv2.blur(img, ksize=(3, 3))
# 高斯滤波,卷积核(5,5)
img_out2 = cv2.GaussianBlur(img, ksize=(5, 5), sigmaX=0, sigmaY=0)
# 中值滤波
img_out3 = cv2.medianBlur(img, 5)

fig, axs = plt.subplots(2, 2)

axs[0, 0].imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
axs[0, 0].set_title('原始图像', fontproperties='SimSun'), axs[0, 0].set_xticks([])
axs[0, 1].imshow(cv2.cvtColor(img_out1, cv2.COLOR_BGR2RGB))
axs[0, 1].set_title('均值滤波', fontproperties='SimSun'), axs[0, 1].set_xticks([])
axs[1, 0].imshow(cv2.cvtColor(img_out2, cv2.COLOR_RGB2BGR))
axs[1, 0].set_title('高斯滤波', fontproperties='SimSun'), axs[1, 0].set_xticks([])
axs[1, 1].imshow(cv2.cvtColor(img_out3, cv2.COLOR_RGB2BGR))
axs[1, 1].set_title('中值滤波', fontproperties='SimSun'), axs[1, 1].set_xticks([])
plt.show()

test2:
 

import cv2
import matplotlib.pyplot as plt

img = cv2.imread('pic.png')

# 均值滤波,卷积核(3,3)
img_out1 = cv2.blur(img, ksize=(3, 3))
# 高斯滤波,卷积核(5,5)
img_out2 = cv2.GaussianBlur(img, ksize=(5, 5), sigmaX=0, sigmaY=0)
# 中值滤波
img_out3 = cv2.medianBlur(img, 5)

fig, axs = plt.subplots(2, 2)

axs[0, 0].imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
axs[0, 0].set_title('原始图像', fontproperties='SimSun'), axs[0, 0].set_xticks([])
axs[0, 1].imshow(cv2.cvtColor(img_out1, cv2.COLOR_BGR2RGB))
axs[0, 1].set_title('均值滤波', fontproperties='SimSun'), axs[0, 1].set_xticks([])
axs[1, 0].imshow(cv2.cvtColor(img_out2, cv2.COLOR_RGB2BGR))
axs[1, 0].set_title('高斯滤波', fontproperties='SimSun'), axs[1, 0].set_xticks([])
axs[1, 1].imshow(cv2.cvtColor(img_out3, cv2.COLOR_RGB2BGR))
axs[1, 1].set_title('中值滤波', fontproperties='SimSun'), axs[1, 1].set_xticks([])
plt.show()

test3

import cv2
import numpy as np

# 读取图像
img = cv2.imread('pic1.png', cv2.IMREAD_GRAYSCALE)

img_med = cv2.medianBlur(img, 5)

# 使用拉普拉斯算子进行图像锐化
laplacian = cv2.Laplacian(img_med, cv2.CV_64F)
laplacian_img = img_med + laplacian

Soble = cv2.Sobel(img_med, cv2.CV_8U, 1, 0, ksize=3)
Soble = np.uint8(np.absolute(Soble))  # 将Sobel结果转换为 uint8 类型

Soble_img = cv2.addWeighted(img_med, 1, Soble, 1, 0)


# 将结果限制在 0-255 范围内
laplacian_img = np.clip(laplacian_img, 0, 255).astype(np.uint8)
Soble_img = np.clip(Soble_img,0,255).astype(np.uint8)
# 显示原始图像和锐化后的图像
cv2.imshow('Original Image', img)
cv2.imshow('laplacian Image', laplacian_img)
cv2.imshow('Soble_img Image', Soble_img)

cv2.waitKey(0)
cv2.destroyAllWindows()