import cv2
import numpy as np
# 载入视频文件
cap = cv2.VideoCapture('C://Users//14812//Desktop//新视野大学英语第三版读写教程 4//刻度//python-ipa-basic-master//bike.mp4')
# 定义压缩比列表
keep_list = [0.5, 0.05, 1]
def apply_compression(fft_shift, compression_ratio):
magnitude = np.abs(fft_shift)
threshold = np.percentile(magnitude, 100 - 100 * compression_ratio)
mask = magnitude > threshold
compressed_fft_shift = fft_shift * mask
return compressed_fft_shift
while True:
# 读取一帧图像
ret, frame = cap.read()
# 如果没有读取到帧则退出循环
if not ret:
break
# 灰度影像
gray_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# 傅里叶变换
fft = np.fft.fft2(gray_frame)
fft_shift = np.fft.fftshift(fft)
for keep_ratio in keep_list:
# 应用压缩
compressed_fft_shift = apply_compression(fft_shift, keep_ratio)
# 逆傅里叶变换
compressed_ifft_shift = np.fft.ifftshift(compressed_fft_shift)
compressed_img = np.fft.ifft2(compressed_ifft_shift)
compressed_img = np.abs(compressed_img)
# 转换为8位无符号整数类型
compressed_img_uint8 = cv2.normalize(compressed_img, None, 0, 255, cv2.NORM_MINMAX, dtype=cv2.CV_8U)
# 显示压缩后的图像
cv2.imshow(f'Compressed Image (Keep Ratio: {keep_ratio})', compressed_img_uint8)
# 等待按键事件或一定的时间,然后关闭所有窗口
if cv2.waitKey(25) & 0xFF == ord('q'):
break
# 释放视频文件
cap.release()
# 关闭所有窗口
cv2.destroyAllWindows()
这个脚本从指定目录读取名为 "bike.mp4" 的视频文件,使用快速傅里叶变换 (FFT) 进行压缩,并显示压缩后的图像。
以下是代码的简要概述:
1、导入必要的库:OpenCV(cv2)和 NumPy。
2、使用 cv2.VideoCapture 加载视频文件。
3、定义压缩比列表。
创建一个名为 apply_compression 的函数,该函数接受平移后的 FFT 和压缩比作为输入,并在应用基于幅度阈值的掩模后返回压缩后的 FFT。
4、创建一个名为 apply_compression 的函数,该函数接受平移后的 FFT 和压缩比作为输入,并在应用基于幅度阈值的掩模后返回压缩后的 FFT。
5、遍历视频的每一帧。
6、将帧转换为灰度图像。
7、应用 FFT,并使用 np.fft.fftshift 将零频率分量移至频谱的中心。
8、遍历 keep_list 中的压缩比。
9、应用 apply_compression 函数以压缩 FFT。
10、使用 np.fft.ifft2 执行逆 FFT,并使用 np.fft.ifftshift 将零频率分量移回原始位置。
11、将压缩图像转换为 8 位无符号整数类型。
12、显示压缩图像及其相应的压缩比。
13、等待按下 'q' 键或经过一定时间(25 毫秒),然后关闭所有窗口。
14、释放视频文件并关闭所有窗口。
该脚本使用不同的压缩比压缩视频的每一帧,并在单独的窗口中显示结果图像。通过使用快速傅里叶变换 (FFT) 将图像转换为频率域来进行压缩,这样在频率域中应用压缩更为简单。
代码的逐行详细解释:
- import cv2: 导入OpenCV库,用于图像处理和显示。
- import numpy as np: 导入NumPy库,用于处理数组和矩阵操作。
- cap = cv2.VideoCapture('C://Users//14812//Desktop//新视野大学英语第三版读写教程 4//刻度//python-ipa-basic-master//bike.mp4'): 使用cv2.VideoCapture打开指定路径下的视频文件。
- keep_list = [0.5, 0.05, 1]: 定义一个列表,包含三个不同的压缩比例。
- def apply_compression(fft_shift, compression_ratio):: 定义一个名为apply_compression的函数,输入为平移后的傅里叶变换图像(fft_shift)和压缩比例(compression_ratio)。
- magnitude = np.abs(fft_shift): 计算平移后的傅里叶变换图像的绝对值(即频谱幅值)。
- threshold = np.percentile(magnitude, 100 - 100 * compression_ratio): 根据压缩比例计算频谱幅值的阈值。例如,如果压缩比例为0.5,则阈值为幅值的50%分位数。
- mask = magnitude > threshold: 创建一个布尔类型的掩码,用于筛选大于阈值的频谱幅值。
- compressed_fft_shift = fft_shift * mask: 将掩码应用于平移后的傅里叶变换图像,将低于阈值的频率分量置零,实现压缩。
- return compressed_fft_shift: 返回压缩后的平移傅里叶变换图像。
- while True:: 开始一个无限循环,用于逐帧处理视频文件。
- ret, frame = cap.read(): 使用cap.read()读取视频文件的当前帧。ret表示读取是否成功,frame表示读取到的帧。
- if not ret: break: 如果读取失败(视频结束),则跳出循环。
- gray_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY): 使用cv2.cvtColor函数将读取到的帧从BGR色彩空间转换为灰度色彩空间。
- fft = np.fft.fft2(gray_frame): 使用np.fft.fft2函数对灰度图像执行二维傅里叶变换。
- fft_shift = np.fft.fftshift(fft): 使用np.fft.fftshift函数对傅里叶变换后的图像进行平移操作,将低频分量移到图像的中央。
- for keep_ratio in keep_list:: 遍历压缩比例列表。
- compressed_fft_shift = apply_compression(fft_shift, keep_ratio): 调用apply_compression函数对平移后的傅里叶变换图像(fft_shift)应用压缩,得到压缩后的平移傅里叶变换图像(compressed_fft_shift)。
- compressed_ifft_shift = np.fft.ifftshift(compressed_fft_shift): 使用np.fft.ifftshift函数将压缩后的平移傅里叶变换图像(compressed_fft_shift)进行逆平移操作,还原低频分量的位置。
- compressed_img = np.fft.ifft2(compressed_ifft_shift): 使用np.fft.ifft2函数对逆平移后的傅里叶变换图像(compressed_ifft_shift)进行二维逆傅里叶变换,从频域转回到空域,得到压缩后的图像。
- compressed_img = np.abs(compressed_img): 由于逆傅里叶变换后的图像可能包含复数值,需要使用np.abs函数计算每个像素的绝对值,确保图像仅包含实数值。
- compressed_img_uint8 = cv2.normalize(compressed_img, None, 0, 255, cv2.NORM_MINMAX, dtype=cv2.CV_8U): 使用cv2.normalize函数将压缩后的图像归一化为8位无符号整数类型,像素值范围为0-255。
- cv2.imshow(f'Compressed Image (Keep Ratio: {keep_ratio})', compressed_img_uint8): 使用cv2.imshow函数显示压缩后的图像,窗口标题显示当前压缩比例。
- if cv2.waitKey(25) & 0xFF == ord('q'): break: 使用cv2.waitKey函数等待25毫秒。如果在这期间按下了'q'键,跳出循环。
- cap.release(): 释放cv2.VideoCapture对象,关闭视频文件。
- cv2.destroyAllWindows(): 关闭所有OpenCV创建的窗口。
- 整个代码主要实现了对视频文件的逐帧处理,对每一帧图像执行傅里叶变换、压缩、逆傅里叶变换等操作。最后,显示不同压缩比例下的压缩后图像。在处理过程中,通过阈值筛选频谱幅值,达到压缩的目的。
部分代码详解:
def apply_compression(fft_shift, compression_ratio):
magnitude = np.abs(fft_shift)
threshold = np.percentile(magnitude, 100 - 100 * compression_ratio)
mask = magnitude > threshold
compressed_fft_shift = fft_shift * mask
return compressed_fft_shift
这是一个名为 apply_compression 的自定义函数,用于对平移后的快速傅里叶变换(FFT)数据进行压缩。其主要目的是在频率域中实现有损图像压缩,同时保留图像的主要结构和信息。具体来说,它保留了给定压缩比例下最重要(具有较大幅度)的频率成分,而去除了较小幅度的成分。
函数接受两个参数:
fft_shift - 经过平移的 FFT 数据。
compression_ratio - 一个表示压缩程度的浮点数,取值范围为 0 到 1。
在函数中,首先计算 FFT 数据的幅度,然后根据压缩比例设置幅度阈值。接下来,创建一个掩模以区分高于阈值的幅度元素(保留)和低于阈值的元素(去除)。最后,将掩模应用于平移后的 FFT 数据,以实现压缩。
这个函数在图像处理领域具有重要意义,因为它可以用于实现基于频率域的有损图像压缩。这种压缩方法在许多应用中都非常实用,例如缩减图像文件大小、加快图像传输速度和降低存储空间需求。
以下是该函数的步骤:
1、计算 fft_shift 的幅度(即复数的绝对值)。
magnitude = np.abs(fft_shift)
在这个项目中,我们需要计算平移后的快速傅里叶变换(FFT)数据 fft_shift 的幅度,因为我们的目标是根据幅度对频率成分进行筛选。计算幅度有助于我们区分 FFT 数据中的强频率成分和弱频率成分。
FFT 数据通常包含复数值,每个复数值表示一个特定频率成分的振幅(幅度)和相位。幅度反映了频率成分在图像中的重要性或能量,相位表示了频率成分的位置或相对排列。
在图像压缩中,我们主要关注幅度,因为较大的幅度值对应的频率成分对图像的结构和信息有更大的贡献。通过保留具有较大幅度的频率成分并去除较小幅度的频率成分,我们可以实现有损压缩,同时保留图像的主要信息。
因此,在 apply_compression 函数中,我们计算 fft_shift 的幅度,以便根据给定的压缩比例设置幅度阈值,并创建一个相应的掩模来保留重要的频率成分。
2、根据 compression_ratio 计算幅度阈值。阈值是幅度分布中位于 (100 - 100 * compression_ratio) 百分位数的值。
threshold = np.percentile(magnitude, 100 - 100 * compression_ratio)
3、创建一个掩模,其中高于阈值的幅度元素为 True,低于阈值的元素为 False。
mask = magnitude > threshold
4、将掩模应用于平移后的 FFT 数据。这会将低于阈值的幅度元素置为 0,保留高于阈值的元素。
compressed_fft_shift = fft_shift * mask
5、返回压缩后的 FFT 数据。
return compressed_fft_shift
通过在频率域中保留重要的频率成分并去除不太重要的成分,这个函数实现了图像的压缩。
细析:
1、计算幅度
magnitude = np.abs(fft_shift)
这一步使用 NumPy 的 np.abs 函数计算平移后的 FFT 数据 fft_shift 的幅度。FFT 数据通常包含复数,np.abs 函数返回复数的绝对值,即幅度。
2、计算幅度阀值
threshold = np.percentile(magnitude, 100 - 100 * compression_ratio)
在这一步,我们计算用于压缩的幅度阈值。np.percentile 函数返回数组中给定百分位数的值。我们将 compression_ratio 乘以 100 并从 100 中减去,以确定我们希望保留的幅度百分位数。例如,如果 compression_ratio 为 0.05(即保留 5% 的频率成分),我们将计算 95 百分位数的幅度作为阈值。
3、创建掩膜
mask = magnitude > threshold
接下来,我们创建一个布尔掩模,用于将低于阈值的幅度置为零。mask 是一个与 magnitude 具有相同形状的布尔数组,其中高于阈值的幅度元素为 True,低于阈值的元素为 False。
4、应用掩膜
compressed_fft_shift = fft_shift * mask
在这一步,我们将布尔掩模 mask 应用于平移后的 FFT 数据 fft_shift。由于 mask 是一个布尔数组,当与 fft_shift 相乘时,True 会被转换为 1,False 会被转换为 0。因此,高于阈值的幅度元素会被保留,而低于阈值的元素会被置为 0。这样就实现了频率域数据的压缩。
5、返回压缩后的FFT数据
return compressed_fft_shift
最后,函数返回压缩后的 FFT 数据。此数据可以用于逆傅里叶变换,以生成压缩后的图像。
compressed_ifft_shift = np.fft.ifftshift(compressed_fft_shift)
compressed_img = np.fft.ifft2(compressed_ifft_shift)
compressed_img = np.abs(compressed_img)
compressed_ifft_shift = np.fft.ifftshift(compressed_fft_shift): 使用np.fft.ifftshift函数将经过压缩的频域图像(compressed_fft_shift)进行逆平移操作。这个操作将低频分量从图像中心移回到原始位置。
compressed_img = np.fft.ifft2(compressed_ifft_shift): 使用np.fft.ifft2函数对逆平移后的频域图像(compressed_ifft_shift)执行逆傅里叶变换。这一步将图像从频域转换回到空域,得到压缩后的图像。
compressed_img = np.abs(compressed_img): 由于逆傅里叶变换后的图像可能包含复数值,因此需要使用np.abs函数计算图像中每个像素的绝对值。这样可以确保压缩后的图像仅包含实数值,便于后续处理和显示。