1.灰度变换(线性)
在图像处理领域,灰度变换是一种基础且重要的操作,它能够改变图像的灰度分布,从而实现图像增强、对比度调整等目的。今天,我们将深入探讨通过 Python 代码实现图像灰度的线性变换。
代码实现
首先,让我们来看看实现这一功能的代码。代码主要借助了两个强大的库:matplotlib 库中的 pyplot 模块用于绘图,以及 OpenCV 库用于图像处理。
import matplotlib.pyplot as plt
import cv2
img = cv2.imread('001.bmp', 0)
a, b = 1, 0
img1 = cv2.add(cv2.multiply(img, a), b)
代码开头,我们导入了所需的库。接着,使用cv2.imread函数读取图像文件'001.bmp',并以灰度模式读取(第二个参数0表示灰度模式),将读取的图像存储在变量img中。然后定义了两个变量a和b,这里初始赋值为1和0,这两个变量将用于后续的图像灰度变换公式y = ax + b(其中x是原图像像素值,y是变换后的像素值)。通过cv2.multiply函数将图像每个像素值乘以a,再使用cv2.add函数加上b,从而得到新的图像img1。
接下来的代码部分,通过循环展示了不同a和b值下的图像变换效果。
plt.subplot(231)
plt.imshow(img, cmap='gray')
plt.title('a=1,b=0')
img1=cv2.add(cv2.multiply(a,img),b)
plt.subplot(232)
plt.imshow(img1,cmap='gray')
plt.title('a=1,b=50')
a,b=1,-50
img1=cv2.add(cv2.multiply(a,img),b)
plt.subplot(233)
plt.imshow(img1,cmap='gray')
plt.title('a=1,b=-50')
a,b=1.5,0
img1=cv2.add(cv2.multiply(a,img),b)
plt.subplot(234)
plt.imshow(img1,cmap='gray')
plt.title('a=1.5,b=0')
a,b=0.3,0
img1=cv2.add(cv2.multiply(a,img),b)
plt.subplot(235)
plt.imshow(img1,cmap='gray')
plt.title('a=0.3,b=0')
a,b=-1,0
img1=a*img+b
plt.subplot(236)
plt.imshow(img1,cmap='gray')
plt.title('a=-1,b=0')
plt.show()
使用plt.subplot函数创建了一个 2 行 3 列的子图布局,以便在同一窗口中展示不同参数下的变换结果。通过plt.imshow函数依次显示原图像和经过不同线性变换后的图像,并使用plt.title为每个子图添加标题,注明对应的a和b值。
变换效果分析
- a = 1, b = 0:这种情况下,变换公式y = ax + b实际上就是y = x,即图像没有发生任何变化,原图像被直接显示。
- a = 1, b = 50:此时变换后的像素值y = x + 50,图像整体变亮,因为每个像素值都增加了 50。
- a = 1, b = -50:变换公式为y = x - 50,图像整体变暗,所有像素值都减少了 50。
- a = 1.5, b = 0:公式为y = 1.5x,图像对比度增强,亮的部分变得更亮,暗的部分也相对更暗。
- a = 0.3, b = 0:y = 0.3x,图像对比度降低,整体变得更灰暗,因为像素值都被缩小到原来的 0.3 倍。
- a = -1, b = 0:y = -x,图像呈现出负片效果,亮暗颠倒。
通过这段代码,我们直观地看到了线性变换参数a和b对图像灰度的影响,这为我们在图像处理中根据实际需求灵活调整图像提供了有力的手段。无论是增强图像细节,还是调整图像的整体亮度和对比度,灰度线性变换都能发挥重要作用。
2.灰度变换(非线性)、
在图像处理的广阔领域中,除了常见的线性变换,非线性变换同样占据着举足轻重的地位。它能够以更为复杂且独特的方式对图像的灰度分布进行重塑,为图像带来丰富多样的变化效果,满足不同场景下的图像处理需求。接下来,我们将深入剖析通过 Python 代码实现图像灰度非线性变换的过程。
代码展示
## 图像灰度变换(非线性变换)
import cv2
import matplotlib.pyplot as plt
img=cv2.imread('001.bmp',0)
img=img/255
plt.subplot(121)
plt.imshow(img,cmap='gray')
plt.title('original')
r=0.4
plt.subplot(122)
temp=cv2.pow(img,r)
plt.imshow(temp,cmap='gray')
plt.title('c=1,r=0.4')
plt.show()
代码伊始,我们一如既往地导入了关键的库,即用于图像处理的 OpenCV 库和用于绘图展示的 matplotlib 库中的 pyplot 模块。随后,使用cv2.imread函数读取图像文件'001.bmp',并且以灰度模式(参数0指定)将其存储在变量img中。值得注意的是,这里将图像的像素值进行了归一化处理,通过img = img / 255,把像素值范围从原本的0 - 255映射到了0 - 1区间,这是为后续的非线性变换做准备,因为许多非线性变换函数在归一化的像素值上运算能更好地体现其特性。
接着,代码创建了一个1行2列的子图布局。在第一个子图中,使用plt.imshow函数展示了原图像,并通过plt.title设置标题为original,让我们能够清晰地看到初始图像的模样。
而后,定义了一个参数r = 0.4,这个参数将在后续的非线性变换中起到关键作用。在第二个子图中,利用cv2.pow函数对图像进行了非线性变换,这里的变换公式为y = x^r(其中x是归一化后的原图像像素值,y是变换后的像素值),变换后的结果存储在temp变量中。最后,通过plt.imshow展示变换后的图像,并设置标题为c=1,r=0.4(这里的c=1在当前代码中未体现其实际作用,可能是在更广义的变换公式y = c * x^r中预留的参数位)。
变换效果剖析
当参数r = 0.4时,从变换后的图像效果来看,图像整体变得更加明亮,并且图像的细节得到了一定程度的增强。这是因为对于归一化后的像素值x,当0 < r < 1时,x^r的结果会使得较小的像素值相对增大的幅度更大,而较大的像素值相对增大的幅度较小。例如,原本像素值为0.1的点,经过r = 0.4的变换后,0.1^0.4 ≈ 0.398,像素值增大了接近 4 倍;而原本像素值为0.9的点,0.9^0.4 ≈ 0.955,像素值仅略有增加。这种特性使得图像中较暗区域的灰度值提升更为显著,从而整体上让图像变亮,同时也突出了暗部的细节。
通过这段代码,我们切实感受到了非线性变换在图像灰度处理上的独特魅力,它为我们提供了一种区别于线性变换的思路,能够根据不同的参数设置创造出各种独特的图像效果,为图像处理工作注入了更多的灵活性和创造性。
3.图像代数运算(加法运算)
在图像处理的技术体系里,代数运算作为一种基础操作,能够实现诸多有趣且实用的功能。今天,我们聚焦于图像的加法运算,深入探讨其在 Python 中的实现方式以及实际应用效果。
## 图像代数运算(加法运算)
import cv2
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# Define the GaussianNoise function
def GaussianNoise(image, mean, var):
image = np.array(image/255, dtype=float)
noise = np.random.normal(mean, var ** 0.5, image.shape)
out = image + noise
if out.min() < 0:
low_clip = -1.
else:
low_clip = 0.
out = np.clip(out, low_clip, 1.0)
out = np.uint8(out*255)
return out
img = cv2.imread('002.bmp', 0)
img = np.array(img)
img.flags.writeable = True
img1 = img/255
img_n = GaussianNoise(img1, 0, 0.05)
plt.subplot(131)
plt.imshow(img, cmap='gray')
plt.title('original')
plt.subplot(132)
plt.imshow(img1, cmap='gray')
plt.title('带噪声图片')
k = np.zeros([img.shape[0], img.shape[1]])
for i in range(100):
j = GaussianNoise(img, 0, 0.05)
k = k + j
k = k/100
plt.subplot(133)
plt.imshow(k, 'gray')
plt.title('去噪声')
plt.show()
代码开篇,导入了 OpenCV、NumPy 和 matplotlib.pyplot 这几个核心库。OpenCV 用于图像读取等基础操作,NumPy 提供了高效的数值计算功能,matplotlib.pyplot 则负责图像的可视化展示。此外,通过设置plt.rcParams,确保了中文显示正常且坐标轴负号能正确呈现。
接着定义了GaussianNoise函数,该函数的作用是为输入图像添加高斯噪声。在函数内部,先将图像像素值归一化到 0 - 1 范围,然后利用np.random.normal生成符合高斯分布的噪声,其均值为mean,标准差为var ** 0.5。将噪声与原图像相加后,通过np.clip函数确保结果像素值在合理范围内,最后再转换回 0 - 255 的整数形式并返回。
随后读取图像'002.bmp'并转换为 NumPy 数组,且设置其可写属性。将图像归一化后,调用GaussianNoise函数为图像添加噪声,得到含噪图像img_n。利用plt.subplot创建了一个 1 行 3 列的子图布局,在第一个子图展示原图像,第二个子图展示添加噪声后的图像。
在去噪部分,初始化一个全零数组k,其大小与原图像一致。通过 100 次循环,每次生成一个含噪图像并累加到k中,最后将累加结果平均,得到去噪后的图像k,并在第三个子图中展示。
运算效果解读
- 添加噪声:从第二个子图的带噪声图片可以明显看到,图像上布满了随机分布的噪点。这是因为高斯噪声在图像上表现为随机的亮度变化,由于设置的均值为 0,噪声围绕着原图像像素值上下波动,标准差0.05决定了噪声的波动幅度,使得图像细节被噪声干扰,视觉效果变差。
- 去噪尝试:第三个子图展示的去噪图像虽然没有完全恢复到原图像的清晰状态,但相比带噪声图片,噪点明显减少。这种去噪方法的原理基于大数定律,多次独立生成的高斯噪声在累加求平均后,噪声的随机性相互抵消。因为每次噪声的均值为 0,大量噪声累加平均后,其对原图像像素值的影响逐渐减弱,从而在一定程度上还原了图像的原本面貌。
通过这段代码,我们清晰地看到了图像加法运算在添加噪声和简单去噪场景中的应用,它为我们进一步理解图像的特性以及开发更复杂的图像处理算法奠定了基础。
4.图像代数运算(减法运算)
import cv2
import numpy as np
import matplotlib.pyplot as plt
def GaussianNoise(img,means,sigma):
for i in range(img.shape[0]):
for j in range(img.shape[1]):
img[i,j]=img[i,j]+sigma*np.random.normal(means,sigma)
return img
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
img=cv2.imread('002.bmp',0)
img=img/255
img_n=GaussianNoise(img,0,0.1)
K=img_n-img
plt.subplot(131)
plt.imshow(img,'gray')
plt.title('有噪声图片')
plt.subplot(132)
plt.imshow(img_n,cmap='gray')
plt.title('原始图片')
plt.subplot(133)
plt.imshow(K,'gray')
plt.title('噪声')
plt.show()
添加噪声:从第二个子图的带噪声图片可以明显看到,图像上布满了随机分布的噪点。这是因为高斯噪声在图像上表现为随机的亮度变化,由于设置的均值为 0,噪声围绕着原图像像素值上下波动,标准差0.05决定了噪声的波动幅度,使得图像细节被噪声干扰,视觉效果变差。
去噪尝试:第三个子图展示的去噪图像虽然没有完全恢复到原图像的清晰状态,但相比带噪声图片,噪点明显减少。这种去噪方法的原理基于大数定律,多次独立生成的高斯噪声在累加求平均后,噪声的随机性相互抵消。因为每次噪声的均值为 0,大量噪声累加平均后,其对原图像像素值的影响逐渐减弱,从而在一定程度上还原了图像的原本面貌。
5.图像代数运算(乘法运算)
import numpy as np
import cv2
import matplotlib.pyplot as plt
# 设置中文字体和负号显示
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 读取图像,以灰度模式读取
img = cv2.imread('001.bmp', 0)
# 使用multiply函数进行图像的乘运算
img1 = cv2.multiply(1.2, img)
img2 = cv2.multiply(5, img)
# 创建子图布局
plt.subplot(131)
plt.imshow(img, 'gray')
plt.title('原始图片')
plt.subplot(132)
plt.imshow(img1, 'gray')
plt.title('乘以 1.2')
plt.subplot(133)
plt.imshow(img2, 'gray')
plt.title('乘以 5')
# 显示图像
plt.show()
原始图片
显示的是原始的灰度图像,它的像素值保持不变。
乘以 1.2
图像整体亮度有所提升,因为每个像素值都乘以了1.2
,使得图像中的亮部更亮,暗部也相对变亮,但整体的对比度变化不是特别明显。
乘以 5
图像的亮度大幅提升,部分区域可能会出现过曝的现象,即像素值超过了 255,在显示时会被截断为 255,导致这些区域变成白色,丢失了部分细节信息。
通过这个实验,我们可以看到图像乘法运算对图像亮度的影响,并且乘数越大,图像越亮,但也可能会导致细节丢失。在实际应用中,需要根据具体需求选择合适的乘数。、
6.图像代数运算(除法运算)
import cv2
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
img=cv2.imread('001.bmp',0)
img1=cv2.divide(img,2)
img2=cv2.divide(img,4)
img3=cv2.divide(img,8)
plt.subplot(141)
plt.imshow(img,'gray',vmin=0,vmax=255)
plt.title('原始图像')
plt.subplot(142)
plt.imshow(img1,'gray',vmin=0,vmax=255)
plt.title('除以 2')
plt.subplot(143)
plt.imshow(img2,'gray',vmin=0,vmax=255)
plt.title('除以 4')
plt.subplot(144)
plt.imshow(img3,'gray',vmin=0,vmax=255)
plt.title('除以 8')
plt.show()
代码解释
- 同样先导入所需的库,并设置中文字体和负号显示。
- 使用
cv2.imread
以灰度模式读取图像。 cv2.divide
函数用于对图像的每个像素值进行除法运算。分别将原图像除以2
、4
和8
,得到img1
、img2
和img3
。- 创建一个 1 行 4 列的子图布局,依次显示原始图像、除以
2
后的图像、除以4
后的图像和除以8
后的图像,并设置相应的标题。
运行结果分析
- 原始图像:展示的是未经处理的灰度图像。
- 除以 2:图像整体亮度降低,因为每个像素值都变为原来的一半。图像中的亮部和暗部的亮度差距相对缩小,对比度有所降低。
- 除以 4:亮度进一步降低,图像变得更暗,细节可能开始变得模糊,因为像素值进一步减小。
- 除以 8:图像非常暗,大部分细节难以辨认,因为像素值被大幅缩小。
通过图像的除法运算,我们可以看到除数越大,图像越暗,并且可能会丢失一些细节信息。在实际应用中,除法运算可用于降低图像的亮度或者调整图像的对比度。
7.灰度直方图
# 导入 OpenCV 库,用于图像处理
import cv2
# 导入 matplotlib 库的 pyplot 模块,用于绘图和显示图像
import matplotlib.pyplot as plt
# 设置 matplotlib 使用黑体字体来显示中文
plt.rcParams['font.sans-serif'] = ['SimHei']
# 解决 matplotlib 中负号显示为方块的问题
plt.rcParams['axes.unicode_minus'] = False
# 使用 cv2.imread 函数读取指定路径下的图像 '001.bmp',第二个参数 0 表示以灰度模式读取
img = cv2.imread('001.bmp', 0)
# 创建一个 1 行 3 列的子图布局,并选择第 1 个子图进行后续操作
plt.subplot(131)
# 在当前子图中显示灰度图像 img
plt.imshow(img, 'gray')
# 设置当前子图的标题为 '原图'
plt.title('原图')
# 选择 1 行 3 列子图布局中的第 2 个子图
plt.subplot(132)
# 使用 cv2.calcHist 函数计算图像 img 的灰度直方图
# [img] 表示输入图像列表,[0] 表示使用第 0 个通道(灰度图像只有一个通道)
# None 表示不使用掩码,[256] 表示直方图的 bin 数量,[0, 255] 表示像素值的范围
hist = cv2.calcHist([img], [0], None, [256], [0, 255])
# 使用 plt.plot 函数绘制计算得到的灰度直方图
plt.plot(hist)
# 设置当前子图的标题为 '灰度直方图 1'
plt.title('灰度直方图 1')
# 选择 1 行 3 列子图布局中的第 3 个子图
plt.subplot(133)
# 使用 plt.hist 函数绘制图像 img 的灰度直方图
# img.ravel() 将图像数组展平为一维数组,256 表示 bin 数量,[0, 256] 表示像素值的范围
plt.hist(img.ravel(), 256, [0, 256])
# 设置当前子图的标题为 '灰度直方图 2'
plt.title('灰度直方图 2')
# 显示包含三个子图的图像窗口
plt.show()
8.直方图均衡化
# 导入 OpenCV 库,用于图像处理
import cv2
# 导入 matplotlib 库的 pyplot 模块,用于绘图和显示图像
import matplotlib.pyplot as plt
# 以灰度模式读取指定路径下的图像 '001.bmp',并将其赋值给变量 img
img = cv2.imread('001.bmp', 0)
# 对图像 img 的每个像素值加上 150,使图像整体变亮,结果存储在 img_h 中
img_h = cv2.add(img, 150)
# 将图像 img 的每个像素值乘以 0.2,使图像整体变暗,结果存储在 img_l 中
img_l = cv2.multiply(img, 0.2)
# 计算偏亮图像 img_h 的灰度直方图
# [img_h] 表示输入图像列表;[0] 表示计算第 0 个通道(灰度图像只有一个通道)的直方图
# None 表示不使用掩码;[256] 表示直方图的 bin 数量;[0, 256] 表示像素值范围
img_h_t = cv2.calcHist([img_h], [0], None, [256], [0, 256])
# 计算偏暗图像 img_l 的灰度直方图,参数含义同 img_h_t 的计算
img_l_t = cv2.calcHist([img_l], [0], None, [256], [0, 256])
# 对偏亮图像 img_h 进行直方图均衡化处理,增强图像对比度,结果存储在 img_h_h 中
img_h_h = cv2.equalizeHist(img_h)
# 对偏暗图像 img_l 进行直方图均衡化处理,增强图像对比度,结果存储在 img_l_h 中
img_l_h = cv2.equalizeHist(img_l)
# 计算经过直方图均衡化处理后的偏亮图像 img_h_h 的灰度直方图,参数含义同前
img_h_l = cv2.calcHist([img_h_h], [0], None, [256], [0, 256])
# 计算经过直方图均衡化处理后的偏暗图像 img_l_h 的灰度直方图,参数含义同前
img_l_l = cv2.calcHist([img_l_h], [0], None, [256], [0, 256])
plt.subplot(241)
plt.imshow(img_h,'gray')
plt.title('偏亮图')
plt.subplot(242)
plt.imshow(img_h_h,'gray')
plt.title('直方图均衡化后图')
plt.subplot(245)
plt.plot(img_h_t,'gray')
plt.title('偏亮图灰度直方图')
plt.subplot(246)
plt.plot(img_h_l,'gray')
plt.title('均衡化后直方图')
plt.subplot(243)
plt.imshow(img_l,'gray')
plt.title('偏暗图')
plt.subplot(244)
plt.imshow(img_l_h,'gray')
plt.title('直方图均衡化后图')
plt.subplot(247)
plt.plot(img_l_t,'gray')
plt.title('偏暗图灰度直方图')
plt.subplot(248)
plt.plot(img_l_l,'gray')
plt.title('均衡化后灰度图')
9.离散傅里叶变换
import cv2
import numpy as np
import matplotlib.pyplot as plt
# 以灰度模式读取指定路径下的图像 '001.bmp',并将其赋值给变量 img
img = cv2.imread('001.bmp', 0)
# 对图像 img 的像素值进行归一化处理,将其除以 255 使像素值范围在 [0, 1] 之间
# 然后使用 cv2.dft 函数进行离散傅里叶变换,flags=cv2.DFT_COMPLEX_OUTPUT 表示输出为复数形式
# 结果存储在 img_dft 中
img_dft = cv2.dft(img / 255, flags=cv2.DFT_COMPLEX_OUTPUT)
# 使用 np.fft.fftshift 函数将离散傅里叶变换的结果进行中心化处理
# 即将低频分量移到图像中心,方便后续观察和处理,结果存储在 img_cen 中
img_cen = np.fft.fftshift(img_dft)
# 使用 cv2.idft 函数对离散傅里叶变换的结果 img_dft 进行逆离散傅里叶变换
# 得到经过逆变换后的图像数据,存储在 img_s 中
img_s = cv2.idft(img_dft)
# 使用 cv2.magnitude 函数计算离散傅里叶变换结果 img_dft 的幅度谱
# img_dft[:,:,0] 表示实部,img_dft[:,:,1] 表示虚部,结果存储在 img_dft 中
img_dft = cv2.magnitude(img_dft[:, :, 0], img_dft[:, :, 1])
# 同样使用 cv2.magnitude 函数计算中心化后的结果 img_cen 的幅度谱
# img_cen[:,:,0] 表示实部,img_cen[:,:,1] 表示虚部,结果存储在 img_cen 中
img_cen = cv2.magnitude(img_cen[:, :, 0], img_cen[:, :, 1])
# 使用 cv2.magnitude 函数计算逆离散傅里叶变换结果 img_s 的幅度谱
# img_s[:,:,0] 表示实部,img_s[:,:,1] 表示虚部,结果存储在 img_s 中
img_s = cv2.magnitude(img_s[:, :, 0], img_s[:, :, 1])
plt.subplot(141)
plt.imshow(img,'gray')
plt.title('原图')
plt.subplot(142)
plt.imshow(20*np.log(img_dft),'gray')
plt.title('离散傅里叶变换后频谱')
plt.subplot(143)
plt.imshow(20*np.log(img_cen),'gray')
plt.title('中心化后频谱')
plt.subplot(144)
plt.imshow(img_s,'gray')
plt.title('逆变换后图像')
plt.show()
代码解释
- 读取图像并归一化:使用
cv2.imread
以灰度模式读取图像'001.bmp'
,然后将像素值除以 255 进行归一化,使像素值范围在[0, 1]
之间。 - 离散傅里叶变换(DFT):使用
cv2.dft
函数对归一化后的图像进行离散傅里叶变换,设置flags=cv2.DFT_COMPLEX_OUTPUT
,得到复数形式的结果。 - 中心化处理:使用
np.fft.fftshift
函数将离散傅里叶变换的结果进行中心化,把低频分量移到图像中心,便于后续观察和处理。 - 逆离散傅里叶变换(IDFT):使用
cv2.idft
函数对离散傅里叶变换的结果进行逆变换,得到经过逆变换后的图像数据。 - 计算幅度谱:使用
cv2.magnitude
函数分别计算离散傅里叶变换结果、中心化后的结果以及逆变换结果的幅度谱。 - 显示图像:使用
plt.subplot
创建一个 1 行 4 列的子图布局,依次显示原图、离散傅里叶变换后频谱、中心化后频谱和逆变换后图像,并设置相应的标题。
运行结果分析
- 原图:展示的是原始的灰度图像。
- 离散傅里叶变换后频谱:显示了图像的频域信息,但由于低频分量通常集中在图像的四个角,所以频谱看起来不太直观。
- 中心化后频谱:将低频分量移到了图像中心,使得频谱更加直观。低频分量代表图像的整体轮廓和缓慢变化的部分,高频分量代表图像的细节和边缘信息。
- 逆变换后图像:经过逆离散傅里叶变换得到的图像,理论上应该和原图接近,但可能会存在一些数值误差。
通过离散傅里叶变换,我们可以将图像从空间域转换到频域,从而在频域中对图像进行处理,例如滤波操作。
10.离散余弦变换
import cv2
import numpy as np
import matplotlib.pyplot as plt
# 以灰度模式读取图像
img = cv2.imread('001.bmp', 0)
# 检查图像的高度和宽度是否为奇数
height, width = img.shape
if height % 2 != 0:
# 如果高度为奇数,在图像底部添加一行像素值为 0 的像素
img = cv2.copyMakeBorder(img, 0, 1, 0, 0, cv2.BORDER_CONSTANT, value=0)
if width % 2 != 0:
# 如果宽度为奇数,在图像右侧添加一列像素值为 0 的像素
img = cv2.copyMakeBorder(img, 0, 0, 0, 1, cv2.BORDER_CONSTANT, value=0)
# 对图像进行归一化处理,将像素值缩放到 [0, 1] 范围
img_normalized = img / 255
# 进行离散余弦变换
img_dft = cv2.dct(img_normalized)
# 进行逆离散余弦变换
img_s = cv2.idct(img_dft)
# 显示原始图像、离散余弦变换后的频谱以及逆变换后的图像
plt.subplot(131)
plt.imshow(img, 'gray')
plt.title('原始图像')
plt.subplot(132)
plt.imshow(20 * np.log(abs(img_dft)), 'gray')
plt.title('离散余弦变换后频谱')
plt.subplot(133)
plt.imshow(img_s, 'gray')
plt.title('逆变换后图像')
plt.show()
代码解释
- 读取图像并调整尺寸:使用
cv2.imread
以灰度模式读取图像。为了满足离散余弦变换的要求,检查图像的高度和宽度是否为奇数,如果是则使用cv2.copyMakeBorder
函数在图像底部或右侧添加一行或一列像素值为 0 的像素。 - 归一化处理:将图像的像素值除以 255,将其缩放到
[0, 1]
范围。 - 离散余弦变换(DCT):使用
cv2.dct
函数对归一化后的图像进行离散余弦变换。离散余弦变换是一种将图像从空间域转换到频域的方法,常用于图像压缩等领域。 - 逆离散余弦变换(IDCT):使用
cv2.idct
函数对离散余弦变换的结果进行逆变换,得到经过逆变换后的图像数据。 - 显示图像:使用
plt.subplot
创建一个 1 行 3 列的子图布局,依次显示原始图像、离散余弦变换后的频谱以及逆变换后的图像,并设置相应的标题。
运行结果分析
- 原始图像:展示的是未经处理的灰度图像。
- 离散余弦变换后频谱:显示了图像在频域的信息。低频分量通常集中在频谱的左上角,代表图像的整体轮廓和缓慢变化的部分;高频分量则分布在频谱的右下角,代表图像的细节和边缘信息。
- 逆变换后图像:经过逆离散余弦变换得到的图像,理论上应该和原始图像相似,但可能会因为数值计算的误差而存在一些细微的差异。
离散余弦变换在图像压缩中有着广泛的应用,例如 JPEG 图像压缩标准就使用了离散余弦变换来减少图像的数据量。