当前位置: 首页 > news >正文

傅里叶变换实战:图像去噪与边缘提取

傅里叶变换在图像处理中的应用与实践详解(超详细教程+实战代码)

🚀 本文从零开始详解傅里叶变换在图像处理中的应用,手把手教你实现图像去噪与边缘提取!全文配套Python代码,新手也能轻松上手!

一、傅里叶变换:图像处理的"透视镜"

在图像处理领域,傅里叶变换就像一把神奇的"透视镜",它能让我们透过表象看到图像的本质。通过傅里叶变换,我们可以将图像从空间域(我们肉眼看到的样子)转换到频率域(图像在不同频率下的分解组成),从而用全新的视角观察和处理图像。

1.1 傅里叶变换原理简介

傅里叶变换的核心思想是:任何信号都可以分解为不同频率正弦波的叠加。对于图像这种二维信号,我们使用二维离散傅里叶变换(DFT):

F ( u , v ) = ∑ x = 0 M − 1 ∑ y = 0 N − 1 f ( x , y ) ⋅ e − j 2 π ( u x M + v y N ) F(u,v) = \sum_{x=0}^{M-1} \sum_{y=0}^{N-1} f(x,y) \cdot e^{-j2\pi(\frac{ux}{M}+\frac{vy}{N})} F(u,v)=x=0M1y=0N1f(x,y)ej2π(Mux+Nvy)

🔍 生活化理解:想象你在看一幅画。普通人看到的是整体画面,而傅里叶变换就像把这幅画拆解成不同的组成部分:大块色彩区域(低频部分)和精细纹理细节(高频部分)。就像音乐可以分解为低音、中音和高音一样,图像也可以分解为不同的频率成分。

1.2 为什么要使用频域处理?

在频域处理图像有三大优势:

  1. 分离特征:图像的不同特征(背景、纹理、边缘、噪声)在频域中被清晰分开
  2. 简化计算:某些复杂的空域运算(如卷积)在频域中变成简单的乘法
  3. 针对性处理:可以有选择地处理图像的特定频率成分(例如只去除噪声)

试想:如果要从一桶混合的彩色弹珠中挑出特定颜色,你是一颗一颗筛选快,还是先按颜色分类再整批处理快?频域处理就是这种"分类处理"的思路。

1.3 图像频率的直观解释

在谈图像频率时,我们实际上在讨论图像中像素值变化的快慢:

  • 低频:表示图像中灰度值变化缓慢的区域,如蓝天、墙面等大面积颜色相近的区域
  • 高频:表示图像中灰度值变化剧烈的区域,如物体边缘、细节纹理和噪声

简而言之,像素值变化越剧烈的区域,其频率成分就越高。这就是为什么噪声和边缘在频域中都表现为高频信息。

二、实战目标:椒盐噪声去除与边缘提取

本文将通过一个实际案例,带你掌握傅里叶变换在图像处理中的应用。我们将:

  1. 🔍 将带椒盐噪声的图像转换到频域空间

  2. 🧹 设计并应用低通滤波器去除噪声

  3. ✏️ 使用高通滤波器提取图像边缘信息

  4. 📊 直观比较不同处理方法的效果

    在这里插入图片描述

三、实战代码详解(全中文注释)

import cv2
import numpy as np
import matplotlib.pyplot as pltdef perform_fourier_transform(image):"""执行二维傅里叶变换,将图像从空域转换到频域:param image: 输入灰度图像:return: 频移后的频谱"""# 进行二维傅里叶变换,得到复数形式的频谱f = np.fft.fft2(image)  # 将零频率分量(直流分量)移到频谱中心,便于观察和处理fshift = np.fft.fftshift(f)  return fshiftdef low_pass_filter(fshift, cutoff):"""实现理想低通滤波器,用于保留图像低频信息(如背景、大面积区域),去除高频噪声:param fshift: 频移后的频谱:param cutoff: 截止频率半径(决定保留多少低频信息):return: 滤波后的频谱"""rows, cols = fshift.shape# 找到频谱中心点坐标crow, ccol = rows // 2, cols // 2  # 创建全黑(全零)的掩膜图像mask = np.zeros((rows, cols), np.uint8)  r = cutoffcenter = [crow, ccol]# 创建网格坐标,用于计算每个点到中心的距离x, y = np.ogrid[:rows, :cols]# 创建圆形区域(圆内为1,圆外为0)mask_area = (x - center[0]) ** 2 + (y - center[1]) ** 2 <= r * r# 将圆内区域置为1,表示保留这些频率成分mask[mask_area] = 1  # 将频谱与掩膜相乘,实现低通滤波(保留圆内低频,去除圆外高频)fshift = fshift * mask  return fshiftdef high_pass_filter(fshift, cutoff):"""实现理想高通滤波器,用于保留图像高频信息(如边缘、细节),去除低频信息:param fshift: 频移后的频谱:param cutoff: 截止频率半径(决定去除多少低频信息):return: 滤波后的频谱"""rows, cols = fshift.shape# 找到频谱中心点坐标crow, ccol = rows // 2, cols // 2  # 创建全白(全1)的掩膜图像mask = np.ones((rows, cols), np.uint8)  r = cutoffcenter = [crow, ccol]# 创建网格坐标,用于计算每个点到中心的距离x, y = np.ogrid[:rows, :cols]# 创建圆形区域(圆内为0,圆外为1)mask_area = (x - center[0]) ** 2 + (y - center[1]) ** 2 <= r * r# 将圆内区域置为0,表示去除这些频率成分mask[mask_area] = 0  # 将频谱与掩膜相乘,实现高通滤波(去除圆内低频,保留圆外高频)fshift = fshift * mask  return fshiftdef inverse_fourier_transform(fshift):"""执行傅里叶逆变换,将图像从频域转回空域:param fshift: 频移后的频谱:return: 空域图像"""# 将频谱中心的零频率分量移回原位f_ishift = np.fft.ifftshift(fshift)  # 执行二维傅里叶逆变换img_back = np.fft.ifft2(f_ishift)  # 取复数的绝对值,得到实际的图像灰度值img_back = np.abs(img_back)  return img_back# 读取待处理的椒盐噪声图像
image_path = (r"C:\Users\W01\Desktop\img\noise\salt-and-pepper noise.png")
image = cv2.imread(image_path, 0)  # 以灰度模式读取图像# 检查图片是否成功读取
if image is None:print(f"无法读取图片,请检查路径是否正确: {image_path}")
else:# 【步骤1】进行傅里叶变换,将图像转换到频域fshift = perform_fourier_transform(image)# 【步骤2】低通滤波去噪(截止频率为30)low_pass_fshift = low_pass_filter(fshift, 30)denoised_image = inverse_fourier_transform(low_pass_fshift)# 【步骤3】高通滤波提取边缘(截止频率为10)high_pass_fshift = high_pass_filter(low_pass_fshift, 10)edge_image = inverse_fourier_transform(high_pass_fshift)# 【步骤4】可视化结果,展示原图、频谱、去噪后图像和边缘图plt.subplot(221), plt.imshow(image, cmap='gray')plt.title('原始椒盐噪声图像'), plt.xticks([]), plt.yticks([])plt.subplot(222), plt.imshow(np.log(1 + np.abs(fshift)), cmap='gray')plt.title('傅里叶变换频谱'), plt.xticks([]), plt.yticks([])plt.subplot(223), plt.imshow(denoised_image, cmap='gray')plt.title('低通滤波去噪后图像'), plt.xticks([]), plt.yticks([])plt.subplot(224), plt.imshow(edge_image, cmap='gray')plt.title('高通滤波提取边缘'), plt.xticks([]), plt.yticks([])# 自动调整子图布局,使其填充整个图像区域plt.tight_layout()  plt.show()

四、深入理解频域处理原理

4.1 图像的频域表示:一种全新视角

当我们将图像转换到频域,实际上是在分析图像中不同频率的变化情况:

  • 低频部分(频谱中心):代表图像中变化缓慢的区域,比如蓝天、墙面等大面积颜色相近的区域
  • 高频部分(频谱边缘):代表图像中变化剧烈的区域,比如物体边缘、细小纹理和噪声

⚙️ 技术细节:频谱图中心亮点(零频率)代表图像的平均亮度,越靠近中心的点表示图像中变化越缓慢的部分,越远离中心的点表示变化越剧烈的部分。

将图像转换到频域的关键代码是:

f = np.fft.fft2(image)  # 二维傅里叶变换
fshift = np.fft.fftshift(f)  # 将零频率移到中心

为什么要将零频率移到中心?
原始的FFT结果将零频率成分放在了左上角,不利于观察和处理。通过fftshift函数,我们将零频率移到频谱中心,这样更符合我们的认知习惯:从中心向外,频率由低到高。

4.2 低通滤波:去除噪声的利器

椒盐噪声的特点:在图像中表现为随机黑白像素点,在频域中则表现为分散在各处的高频成分。

低通滤波的工作原理图解:

在这里插入图片描述

低通滤波步骤:

  1. 在频谱中心画一个圆形区域(保留区)
  2. 将圆内的频率成分保留(乘以1),圆外的成分去除(乘以0)
  3. 进行逆变换,得到去噪后的图像
# 低通滤波关键代码解析
mask = np.zeros((rows, cols), np.uint8)  # 创建黑色蒙版
mask_area = (x - center[0]) ** 2 + (y - center[1]) ** 2 <= r * r  # 圆形区域方程
mask[mask_area] = 1  # 圆内区域置为1
fshift = fshift * mask  # 应用蒙版,保留低频,去除高频

截止频率(cutoff)的选择技巧

  • 较小的值(10-20):过滤更多噪声,但可能损失细节
  • 较大的值(40-60):保留更多细节,但可能无法完全去噪
  • 最佳起点:对于512×512图像,推荐从30开始尝试

4.3 高通滤波:图像边缘提取神器

高通滤波与低通滤波正好相反,它保留高频信息(变化剧烈的部分),去除低频信息(变化平缓的部分),因此特别适合边缘提取。

高通滤波的工作原理图解:

在这里插入图片描述

高通滤波步骤:

  1. 在频谱中心画一个圆形区域(去除区)
  2. 将圆内的频率成分去除(乘以0),圆外的成分保留(乘以1)
  3. 进行逆变换,得到图像边缘
# 高通滤波关键代码解析
mask = np.ones((rows, cols), np.uint8)  # 创建白色蒙版
mask_area = (x - center[0]) ** 2 + (y - center[1]) ** 2 <= r * r  # 圆形区域方程
mask[mask_area] = 0  # 圆内区域置为0
fshift = fshift * mask  # 应用蒙版,去除低频,保留高频

💡 处理技巧:先低通滤波去噪,再高通滤波提取边缘,比直接对有噪声的图像进行高通滤波效果更好。这是因为先去噪可以避免噪声被错误地识别为边缘。

4.4 傅里叶逆变换:从频域回到空域

处理完频域信息后,需要通过逆变换将图像转回空域才能显示:

# 逆变换关键步骤
f_ishift = np.fft.ifftshift(fshift)  # 将频谱中心移回原位
img_back = np.fft.ifft2(f_ishift)    # 二维傅里叶逆变换
img_back = np.abs(img_back)          # 取复数的绝对值

⚠️ 注意:由于傅里叶变换结果是复数,所以必须取绝对值才能得到实际可显示的图像。理论上,如果没有对频谱进行修改,逆变换后应该得到完全相同的原始图像,但由于浮点数计算误差,可能存在微小差异。

五、处理效果与结果分析

5.1 频谱图像的解读

频谱图是傅里叶变换结果的可视化表示:

在这里插入图片描述

频谱图中:

  • 中心亮点:代表图像的平均亮度(DC分量)
  • 亮度分布:亮度越高表示该频率成分在图像中的贡献越大
  • 距离中心的远近:表示频率的高低,越远频率越高
  • 方向信息:反映图像中不同方向的结构特征,例如水平线会在垂直方向上形成亮点

📊 可视化技巧:频谱图的动态范围很大,使用对数变换增强显示效果:np.log(1 + np.abs(fshift))。不加对数变换,中心亮点会极其明亮,而其他区域几乎看不见。

5.2 低通滤波去噪效果分析

低通滤波后的图像特点:

  • ✅ 随机分布的黑白噪声点大幅减少
  • ✅ 大面积区域变得平滑
  • ❗ 图像边缘可能略有模糊
  • ❗ 细节信息可能有所损失

这种效果是低通滤波的典型特征——“去高留低”,即保留图像的基本结构,去除高频变化。

5.3 高通滤波边缘提取效果

高通滤波后的图像特点:

  • ✅ 清晰显示图像中的边缘和轮廓
  • ✅ 背景区域变为暗色
  • ✅ 在去噪后的图像上提取边缘,无噪声干扰
  • ❗ 有些微弱的边缘可能被滤除

这种"去低留高"的处理使得图像边缘和细节被突出显示,是形状识别和特征提取的有效手段。

5.4 实际处理效果展示

下面是一个实际处理案例,我们对一张带椒盐噪声的人像照片进行处理:

  1. 原图:带有明显椒盐噪声的人像照片
  2. 频谱图:可以看到中心有明亮的低频区域,周围分布着噪声的高频成分
  3. 低通滤波结果:噪声明显减少,面部轮廓清晰可见
  4. 高通滤波结果:清晰展示了人脸轮廓和重要特征线条

通过这个例子,我们可以直观感受到频域处理的强大效果。

六、进阶滤波器与优化技巧

6.1 三种常用滤波器比较

除了本文实现的理想滤波器,还有两种常用滤波器:

滤波器类型优缺点实现难度适用场景
理想滤波器截止锐利,但有明显振铃效应简单演示与教学
巴特沃斯滤波器平滑过渡,振铃效应较小中等一般图像处理
高斯滤波器最平滑过渡,几乎无振铃效应中等专业图像处理

下面是巴特沃斯低通滤波器的实现代码:

def butterworth_low_pass_filter(fshift, cutoff, order=2):"""实现巴特沃斯低通滤波器,提供更平滑的过渡效果:param fshift: 频移后的频谱:param cutoff: 截止频率:param order: 滤波器阶数,阶数越高越接近理想滤波器:return: 滤波后的频谱"""rows, cols = fshift.shapecrow, ccol = rows // 2, cols // 2# 创建网格坐标系统u = np.arange(rows)v = np.arange(cols)u, v = np.meshgrid(u - crow, v - ccol, sparse=True)# 计算每个点到中心的距离d = np.sqrt(u**2 + v**2)# 巴特沃斯低通滤波器公式:H(u,v) = 1 / [1 + (D(u,v)/D0)^(2n)]mask = 1 / (1 + (d / cutoff)**(2*order))return fshift * mask

高斯低通滤波器的实现代码:

def gaussian_low_pass_filter(fshift, cutoff):"""实现高斯低通滤波器,提供最平滑的过渡效果:param fshift: 频移后的频谱:param cutoff: 截止频率,决定高斯函数的扩散程度:return: 滤波后的频谱"""rows, cols = fshift.shapecrow, ccol = rows // 2, cols // 2# 创建网格坐标系统u = np.arange(rows)v = np.arange(cols)u, v = np.meshgrid(u - crow, v - ccol, sparse=True)# 计算距中心的距离平方d_square = u**2 + v**2# 高斯低通滤波器公式:H(u,v) = e^[-D²(u,v)/(2D0²)]mask = np.exp(-d_square / (2 * cutoff**2))return fshift * mask

不同滤波器效果比较

  • 理想滤波器:边界锐利,但会产生"振铃效应"(边缘周围出现波纹状伪影)
  • 巴特沃斯滤波器:过渡较为平滑,振铃效应减轻,但计算稍复杂
  • 高斯滤波器:最平滑的过渡,几乎没有振铃效应,是专业图像处理首选

6.2 不同噪声类型的处理策略

不同噪声有不同的频域特性,需要不同的处理方法:

噪声类型频域特点最佳处理方法
椒盐噪声随机分布的高频点低通滤波或中值滤波
高斯噪声广泛分布的高频噪声高斯低通滤波
周期性噪声频谱中特定位置的亮点陷波滤波器(带阻滤波器)
条纹噪声特定方向的线性结构方向性高通滤波器

针对条纹噪声的方向性滤波器示例:

def directional_notch_filter(fshift, angle, width):"""方向性陷波滤波器,用于去除特定方向的条纹噪声:param fshift: 频移后的频谱:param angle: 条纹方向角度(度):param width: 滤波带宽:return: 滤波后的频谱"""rows, cols = fshift.shapecrow, ccol = rows // 2, cols // 2# 创建掩膜mask = np.ones((rows, cols), np.float32)# 将角度转换为弧度theta = np.deg2rad(angle)# 创建网格坐标u, v = np.ogrid[:rows, :cols]u = u - crowv = v - ccol# 计算每个点到中心连线与水平轴的夹角# 注意:arctan2返回的是[-pi, pi]范围内的角度angles = np.arctan2(u, v)# 计算方向性滤波条件(在指定角度附近的点被滤除)# 需要考虑角度的周期性width_rad = np.deg2rad(width)diff = np.minimum(np.abs(angles - theta), np.abs(angles - theta - 2*np.pi))diff = np.minimum(diff, np.abs(angles - theta + 2*np.pi))# 在指定方向上创建陷波(去除该方向的频率成分)mask[diff < width_rad] = 0return fshift * mask

6.3 解决实际问题的综合策略

在实际应用中,我们可以组合多种滤波器实现更复杂的目标:

  1. 渐进式滤波:从小半径开始,逐步增大,观察效果变化
  2. 混合滤波:先用低通滤波去噪,再用陷波滤波去除特定频率干扰
  3. 自适应滤波:根据图像局部特性自动调整滤波参数

例如,处理扫描文档中的摩尔条纹和噪声的综合方案:

def process_scanned_document(image):"""处理扫描文档,去除摩尔条纹和噪声:param image: 输入灰度图像:return: 处理后的图像"""# 步骤1:傅里叶变换fshift = perform_fourier_transform(image)# 步骤2:分析频谱,找出摩尔条纹的主要方向# (这里简化为已知方向为45度)# 步骤3:应用方向性陷波滤波器去除摩尔条纹filtered_fshift = directional_notch_filter(fshift, 45, 5)# 步骤4:应用高斯低通滤波器去除随机噪声filtered_fshift = gaussian_low_pass_filter(filtered_fshift, 30)# 步骤5:逆变换回空域filtered_image = inverse_fourier_transform(filtered_fshift)# 步骤6:增强对比度(可选)filtered_image = cv2.normalize(filtered_image, None, 0, 255, cv2.NORM_MINMAX)return filtered_image.astype(np.uint8)

6.4 频域与空域滤波器对比

频域滤波和空域滤波(如均值滤波、高斯滤波)各有优缺点:

特性频域滤波空域滤波
计算效率大图像更高效小核更高效
理解难度较抽象直观
针对性可针对特定频率难以针对特定特征
全局/局部全局处理局部处理
应用范围去除特定噪声、频率分析简单去噪、模糊锐化

选择合适的方法需要考虑具体问题特点、计算资源和性能要求。

七、实践中的常见问题与解决方案

7.1 如何选择最佳截止频率?

截止频率选择是频域滤波中最关键的参数设置,方法有三:

  1. 可视化检查法

    def visualize_cutoff_effects(image, cutoffs=[10, 30, 50, 70]):"""可视化不同截止频率的效果:param image: 输入图像:param cutoffs: 要测试的截止频率列表:return: 无返回值,直接显示对比结果"""plt.figure(figsize=(15, 8))# 原始图像plt.subplot(2, 3, 1)plt.imshow(image, cmap='gray')plt.title('原始图像')plt.axis('off')# 不同截止频率的效果for i, cutoff in enumerate(cutoffs):fshift = perform_fourier_transform(image)filtered_fshift = low_pass_filter(fshift, cutoff)filtered_image = inverse_fourier_transform(filtered_fshift)plt.subplot(2, 3, i+2)plt.imshow(filtered_image, cmap='gray')plt.title(f'截止频率 = {cutoff}')plt.axis('off')plt.tight_layout()plt.show()
    
  2. 自适应计算法:根据图像能量分布自动计算

    def adaptive_cutoff(fshift, energy_percent=0.90):"""自适应计算截止频率,保留指定百分比的能量:param fshift: 频移后的频谱:param energy_percent: 要保留的能量百分比(0-1):return: 计算出的截止频率"""# 获取频谱中心点rows, cols = fshift.shapecrow, ccol = rows // 2, cols // 2# 计算频谱能量magnitude = np.abs(fshift)total_energy = np.sum(magnitude)# 从中心开始,计算累积能量max_radius = min(rows, cols) // 2cutoff = 1for r in range(1, max_radius):# 创建圆形掩膜y, x = np.ogrid[-crow:rows-crow, -ccol:cols-ccol]mask_area = x*x + y*y <= r*r# 计算圆内能量circle_energy = np.sum(magnitude[mask_area])energy_ratio = circle_energy / total_energy# 如果达到目标能量比例,返回当前半径if energy_ratio >= energy_percent:cutoff = rbreakreturn cutoff
    
  3. 质量评估法:计算信噪比或结构相似性指标

    def evaluate_quality(original, filtered):"""评估滤波结果质量:param original: 原始图像:param filtered: 滤波后图像:return: PSNR值(峰值信噪比)"""# 确保图像类型一致original = original.astype(np.float32)filtered = filtered.astype(np.float32)# 计算PSNRmse = np.mean((original - filtered) ** 2)if mse == 0:psnr = 100else:psnr = 20 * np.log10(255.0 / np.sqrt(mse))# 如果需要计算SSIM,需要导入skimage# from skimage.metrics import structural_similarity as ssim# ssim_value = ssim(original, filtered)return psnr  # 返回PSNR值
    

💡 实用建议:对于新接触的图像类型,先尝试截止频率为图像最小边长的10%作为起点,然后根据效果调整。较好的方法是先用几个不同的截止频率进行测试,选择最佳效果。

7.2 如何解决振铃效应问题?

振铃效应是理想滤波器常见的副作用,表现为图像边缘周围出现波纹状伪影:

在这里插入图片描述

解决方法:

  1. 使用高斯滤波器:最有效的方法,过渡更平滑
  2. 增大截止频率:减小过滤强度,可减轻但不能完全消除
  3. 边缘延拓:处理前扩展图像边界,处理后裁剪回原始大小

高斯滤波器实现代码在6.1节已给出,这里不再重复。

边缘延拓方法示例


def process_with_edge_extension(image, cutoff):"""使用边缘延拓方法减轻振铃效应:param image: 输入图像:param cutoff: 截止频率:return: 处理后的图像"""# 步骤1:使用镜像方式扩展图像边界(减少边缘不连续性)rows, cols = image.shapeextended_image = cv2.copyMakeBorder(image, rows//2, rows//2, cols//2, cols//2, cv2.BORDER_REFLECT)# 步骤2:对扩展后的图像进行傅里叶变换fshift = perform_fourier_transform(extended_image)# 步骤3:应用低通滤波器filtered_fshift = low_pass_filter(fshift, cutoff)# 步骤4:逆变换回空域filtered_extended = inverse_fourier_transform(filtered_fshift)# 步骤5:裁剪回原始尺寸result = filtered_extended[rows//2:rows//2+rows, cols//2:cols//2+cols]return result

🔍 技术解析:边缘延拓通过减少图像边缘的不连续性,有效降低了振铃效应。这是因为振铃效应主要产生于信号的不连续点处,扩展使得图像边缘过渡更加平滑。

7.3 特殊图像的频域处理技巧

7.3.1 医学图像处理

医学影像(如CT、MRI)有其特殊性,需要特别小心处理:

def enhance_medical_image(image):"""医学图像频域增强处理:param image: 输入医学图像:return: 增强后的图像"""# 步骤1:进行傅里叶变换fshift = perform_fourier_transform(image)# 步骤2:保存原始图像用于比较original_mag = np.log(1 + np.abs(fshift))# 步骤3:高频提升滤波(增强边缘但保留低频信息)rows, cols = fshift.shapecrow, ccol = rows // 2, cols // 2# 创建高频提升滤波器掩膜x, y = np.ogrid[:rows, :cols]d_square = ((x - crow) ** 2 + (y - ccol) ** 2).astype(np.float32)# 高频提升滤波器: H(u,v) = a + b·[1 - e^(-c·D²(u,v))]# 其中a控制低频增益,b控制高频增益,c控制截止频率a, b, c = 0.9, 0.1, 0.0025mask = a + b * (1 - np.exp(-c * d_square))# 应用滤波器filtered_fshift = fshift * mask# 步骤4:逆变换enhanced_image = inverse_fourier_transform(filtered_fshift)# 步骤5:归一化处理,增强对比度enhanced_image = cv2.normalize(enhanced_image, None, 0, 255, cv2.NORM_MINMAX)return enhanced_image.astype(np.uint8)

🏥 医学影像处理要点

  1. 保留关键诊断信息是首要原则
  2. 高频提升滤波既能增强边缘(如肿瘤边界),又不会完全丢失低频信息
  3. 处理前务必咨询医学专家,确定需要增强的特征
7.3.2 卫星遥感图像去条纹

卫星图像常见的条纹噪声可通过定向滤波器去除:

def remove_satellite_stripes(image):"""去除卫星图像中的周期性条纹噪声:param image: 输入卫星图像:return: 去条纹后的图像"""# 步骤1:傅里叶变换fshift = perform_fourier_transform(image)# 步骤2:分析频谱,找出条纹特征点# 这里假设已知条纹在水平方向(0度)magnitude_spectrum = np.log(1 + np.abs(fshift))# 步骤3:应用陷波滤波器去除条纹rows, cols = fshift.shapecrow, ccol = rows // 2, cols // 2# 定义垂直带阻滤波器(去除水平条纹)mask = np.ones((rows, cols), np.float32)# 带宽参数width = 5# 在垂直方向上创建带阻区域(去除水平条纹)for i in range(rows):for j in range(cols):# 计算与垂直线的距离dist_from_vertical = abs(j - ccol)# 如果在带阻区域内,则设为0if dist_from_vertical < width and i != crow:mask[i, j] = 0# 应用滤波器filtered_fshift = fshift * mask# 步骤4:逆变换filtered_image = inverse_fourier_transform(filtered_fshift)return filtered_image

🛰️ 卫星图像处理提示

  1. 实际应用中,通常需要分析频谱图找出条纹噪声的具体位置
  2. 通过计算频谱图的行和列平均值,可快速定位噪声点
  3. 对于复杂条纹,可能需要设计多个方向的陷波滤波器

7.4 优化处理性能的方法

随着图像分辨率的提高,性能优化变得越来越重要:

7.4.1 FFT计算优化
def optimized_fft(image):"""优化的FFT计算:param image: 输入图像:return: 频谱"""# 步骤1:调整图像大小为2的幂次,加速FFT计算# FFT算法在图像尺寸为2的幂次时性能最佳h, w = image.shapeoptimal_h = 2**int(np.ceil(np.log2(h)))optimal_w = 2**int(np.ceil(np.log2(w)))# 步骤2:用零填充扩展图像到最优尺寸padded_img = np.zeros((optimal_h, optimal_w), dtype=np.float32)padded_img[:h, :w] = image# 步骤3:使用numpy的FFT计算(底层使用FFTPACK或MKL)f = np.fft.fft2(padded_img)fshift = np.fft.fftshift(f)return fshift, (h, w)
7.4.2 并行处理大型图像

对于大型图像,可以采用分块处理策略:

def parallel_frequency_filter(image, cutoff, filter_type='low', block_size=512):"""并行分块频域滤波处理:param image: 输入图像:param cutoff: 截止频率:param filter_type: 滤波器类型 ('low'或'high'):param block_size: 处理块大小:return: 处理后的图像"""# 获取图像尺寸height, width = image.shape# 创建结果图像result = np.zeros_like(image, dtype=np.float32)# 确定分块数num_blocks_h = int(np.ceil(height / block_size))num_blocks_w = int(np.ceil(width / block_size))# 使用重叠策略避免边界问题overlap = 32  # 重叠像素数# 定义处理单个块的函数def process_block(block, cutoff, filter_type):fshift = perform_fourier_transform(block)if filter_type == 'low':filtered_fshift = low_pass_filter(fshift, cutoff)else:filtered_fshift = high_pass_filter(fshift, cutoff)return inverse_fourier_transform(filtered_fshift)# 分块处理for i in range(num_blocks_h):for j in range(num_blocks_w):# 计算当前块的范围(带重叠)start_h = max(0, i * block_size - overlap)end_h = min(height, (i + 1) * block_size + overlap)start_w = max(0, j * block_size - overlap)end_w = min(width, (j + 1) * block_size + overlap)# 提取当前块block = image[start_h:end_h, start_w:end_w]# 处理当前块processed_block = process_block(block, cutoff, filter_type)# 计算有效区域(去除重叠部分)valid_start_h = max(0, i * block_size)valid_end_h = min(height, (i + 1) * block_size)valid_start_w = max(0, j * block_size)valid_end_w = min(width, (j + 1) * block_size)# 计算有效区域在处理块中的位置block_valid_start_h = valid_start_h - start_hblock_valid_end_h = block_valid_start_h + (valid_end_h - valid_start_h)block_valid_start_w = valid_start_w - start_wblock_valid_end_w = block_valid_start_w + (valid_end_w - valid_start_w)# 将处理结果写入结果图像result[valid_start_h:valid_end_h, valid_start_w:valid_end_w] = \processed_block[block_valid_start_h:block_valid_end_h, block_valid_start_w:block_valid_end_w]return result

💻 性能优化小贴士

  1. 使用numpy的FFT实现通常比手写实现快10-100倍
  2. 对于超大图像(>4K分辨率),分块处理可以有效避免内存溢出
  3. 如追求极致性能,可考虑使用GPU加速库如CuPy或OpenCV的GPU模块

八、高级应用场景与案例解析

8.1 图像压缩的频域实现

JPEG压缩的核心原理就是利用傅里叶变换的特性丢弃高频信息:

def simple_frequency_compression(image, quality=50):"""基于频域的简易图像压缩(模拟JPEG原理):param image: 输入灰度图像:param quality: 质量参数(0-100),值越小压缩率越高:return: 压缩后的图像"""# 步骤1:将图像分成8x8的块h, w = image.shapeblock_size = 8compressed_image = np.zeros_like(image, dtype=np.float32)# 步骤2:保留系数比例(质量参数决定)# 质量越低,保留的系数越少keep_ratio = quality / 100.0# 步骤3:对每个8x8块进行DCT变换并压缩for i in range(0, h, block_size):for j in range(0, w, block_size):# 提取当前块block = image[i:min(i+block_size, h), j:min(j+block_size, w)].copy()# 若块大小不足8x8,用0填充if block.shape[0] < block_size or block.shape[1] < block_size:temp_block = np.zeros((block_size, block_size), dtype=np.float32)temp_block[:block.shape[0], :block.shape[1]] = blockblock = temp_block# 执行DCT变换(离散余弦变换,是傅里叶变换的一种变体)dct_block = cv2.dct(block.astype(np.float32))# 通过阈值化实现压缩(保留较大系数)threshold = np.max(np.abs(dct_block)) * (1 - keep_ratio)dct_block[np.abs(dct_block) < threshold] = 0# 执行IDCT变换(逆变换)idct_block = cv2.idct(dct_block)# 将结果写回原图像compressed_image[i:min(i+block_size, h), j:min(j+block_size, w)] = \idct_block[:min(i+block_size, h)-i, :min(j+block_size, w)-j]return compressed_image

🗜️ 图像压缩原理

  1. JPEG压缩的本质是丢弃人眼不敏感的高频信息
  2. DCT变换(离散余弦变换)是傅里叶变换的一种特殊形式,更适合图像压缩
  3. 图像质量和文件大小可通过保留系数的多少来调节

8.2 水印添加与检测

频域水印是一种隐蔽性好、抗攻击能力强的数字水印技术:

def add_frequency_watermark(image, watermark_text="版权所有"):"""在图像频域添加水印:param image: 输入图像:param watermark_text: 水印文本:return: 添加水印后的图像"""# 步骤1:将图像转换到频域fshift = perform_fourier_transform(image)# 步骤2:生成水印(这里简化为在频域中心区域添加简单模式)rows, cols = fshift.shapecrow, ccol = rows // 2, cols // 2# 水印强度(较小的值使水印不可见但可检测)alpha = 0.1# 在频谱的中频区域添加水印模式for i in range(len(watermark_text)):char_value = ord(watermark_text[i])# 对每个字符,在不同位置添加标记angle = 2 * np.pi * i / len(watermark_text)radius = 50  # 距中心的距离x = int(crow + radius * np.cos(angle))y = int(ccol + radius * np.sin(angle))# 修改幅值,添加水印信息fshift[x, y] = fshift[x, y] * (1 + alpha * char_value)# 步骤3:逆变换回空域watermarked_image = inverse_fourier_transform(fshift)return watermarked_image

检测水印的函数:

def detect_frequency_watermark(image, watermark_text="版权所有"):"""检测图像中的频域水印:param image: 待检测图像:param watermark_text: 预期水印文本:return: 检测结果(True/False)和置信度"""# 步骤1:将图像转换到频域fshift = perform_fourier_transform(image)# 步骤2:检查水印位置的频谱特征rows, cols = fshift.shapecrow, ccol = rows // 2, cols // 2# 用于存储检测到的字符值detected_chars = []# 检测水印for i in range(len(watermark_text)):angle = 2 * np.pi * i / len(watermark_text)radius = 50x = int(crow + radius * np.cos(angle))y = int(ccol + radius * np.sin(angle))# 提取当前位置的幅值magnitude = np.abs(fshift[x, y])# 检查周围区域的平均幅值nearby_points = []for dx in range(-2, 3):for dy in range(-2, 3):if dx == 0 and dy == 0:continuenearby_points.append(np.abs(fshift[x+dx, y+dy]))avg_magnitude = np.mean(nearby_points)# 根据幅值差异估计嵌入的字符值alpha = 0.1  # 与添加时相同的强度estimated_char_value = int((magnitude / avg_magnitude - 1) / alpha)detected_chars.append(estimated_char_value)# 步骤3:比较检测到的字符与预期水印expected_chars = [ord(c) for c in watermark_text]# 计算置信度(字符值的相似度)confidence = np.mean([1 - min(abs(d - e) / 255, 1) for d, e in zip(detected_chars, expected_chars)])# 判断是否检测到水印(置信度阈值可调)is_detected = confidence > 0.7return is_detected, confidence

🔐 频域水印特点

  1. 不可见性:频域水印对图像视觉质量影响极小
  2. 鲁棒性:即使图像经过剪裁、压缩等处理,频域水印仍可能被检测
  3. 适用场景:版权保护、防伪溯源、隐写术等

8.3 基于频谱分析的图像分类

频谱特征可用于图像分类和识别:

def extract_frequency_features(image):"""提取图像的频域特征用于分类:param image: 输入灰度图像:return: 频域特征向量"""# 步骤1:预处理(标准化尺寸和亮度)image = cv2.resize(image, (256, 256))image = cv2.normalize(image, None, 0, 255, cv2.NORM_MINMAX)# 步骤2:傅里叶变换fshift = perform_fourier_transform(image)magnitude = np.abs(fshift)# 步骤3:提取环形频谱特征features = []rows, cols = magnitude.shapecrow, ccol = rows // 2, cols // 2# 定义多个环形区域,计算每个环上的能量# 这些环对应不同频率范围的能量分布ring_radii = [5, 10, 20, 30, 50, 70, 100]for i in range(len(ring_radii)):inner_radius = ring_radii[i-1] if i > 0 else 0outer_radius = ring_radii[i]# 创建环形掩膜y, x = np.ogrid[-crow:rows-crow, -ccol:cols-ccol]ring_mask = (x*x + y*y >= inner_radius**2) & (x*x + y*y < outer_radius**2)# 计算环内能量ring_energy = np.sum(magnitude[ring_mask])features.append(ring_energy)# 步骤4:提取方向性特征(检测是否存在特定方向的结构)num_directions = 8direction_features = []for d in range(num_directions):angle = d * np.pi / num_directionsdirection_mask = np.zeros_like(magnitude, dtype=bool)# 创建扇形区域for r in range(1, min(rows, cols)//2):for theta in np.linspace(angle-0.2, angle+0.2, 20):x = int(ccol + r * np.cos(theta))y = int(crow + r * np.sin(theta))if 0 <= x < cols and 0 <= y < rows:direction_mask[y, x] = True# 计算该方向上的能量direction_energy = np.sum(magnitude[direction_mask])direction_features.append(direction_energy)# 合并所有特征all_features = features + direction_features# 步骤5:归一化特征向量all_features = np.array(all_features)all_features = all_features / np.sum(all_features)return all_features

📊 频域特征分类应用

  1. 纹理分类:不同纹理在频域有明显不同的能量分布
  2. 自然场景识别:自然场景和人造场景在频谱特征上差异明显
  3. 文档分类:文本、图表、照片等在频域特征上各不相同

九、总结与进阶路径

9.1 本文要点回顾

通过本文的学习,我们掌握了:

  1. 傅里叶变换的基本原理:将图像从空间域转换到频率域
  2. 频域滤波的核心思想:在频域中选择性地保留或去除特定频率成分
  3. 实战技能
    • 低通滤波去除椒盐噪声
    • 高通滤波提取图像边缘
    • 不同类型滤波器的选择与应用
  4. 进阶应用
    • 特殊图像的处理技巧
    • 性能优化方法
    • 频域水印、压缩等实际应用

9.2 学习路径与进阶建议

如果你想在图像处理领域更进一步,推荐以下学习路径:

  1. 基础原理深化

    • 学习连续傅里叶变换和离散傅里叶变换的数学原理
    • 掌握小波变换(Wavelet Transform)等更先进的变换方法
  2. 工具与库

    • 熟练使用OpenCV的更多频域处理功能
    • 了解Scikit-image中的高级滤波算法
    • 探索GPU加速库如CuPy等
  3. 应用领域扩展

    • 医学图像分析
    • 计算机视觉中的目标检测与识别
    • 深度学习中的频域特征提取

🔗 推荐学习资源

  1. 《数字图像处理》- 冈萨雷斯(Gonzalez)著
  2. OpenCV官方教程: https://docs.opencv.org/
  3. 斯坦福大学CS131课程: Computer Vision

9.3 代码复用与实践建议

为了方便大家在实际项目中应用本文的代码,我将核心功能封装为一个简单的类:

class FrequencyImageProcessor:"""频域图像处理工具类"""def __init__(self):pass@staticmethoddef fft(image):"""执行二维傅里叶变换"""f = np.fft.fft2(image)fshift = np.fft.fftshift(f)return fshift@staticmethoddef ifft(fshift):"""执行傅里叶逆变换"""f_ishift = np.fft.ifftshift(fshift)img_back = np.fft.ifft2(f_ishift)img_back = np.abs(img_back)return img_back@staticmethoddef ideal_low_pass(fshift, cutoff):"""理想低通滤波器"""rows, cols = fshift.shapecrow, ccol = rows // 2, cols // 2mask = np.zeros((rows, cols), np.uint8)y, x = np.ogrid[-crow:rows-crow, -ccol:cols-ccol]mask_area = x**2 + y**2 <= cutoff**2mask[mask_area] = 1return fshift * mask@staticmethoddef ideal_high_pass(fshift, cutoff):"""理想高通滤波器"""rows, cols = fshift.shapecrow, ccol = rows // 2, cols // 2mask = np.ones((rows, cols), np.uint8)y, x = np.ogrid[-crow:rows-crow, -ccol:cols-ccol]mask_area = x**2 + y**2 <= cutoff**2mask[mask_area] = 0return fshift * mask@staticmethoddef gaussian_low_pass(fshift, cutoff):"""高斯低通滤波器"""rows, cols = fshift.shapecrow, ccol = rows // 2, cols // 2y, x = np.ogrid[-crow:rows-crow, -ccol:cols-ccol]d_square = x**2 + y**2mask = np.exp(-d_square / (2 * cutoff**2))return fshift * maskdef remove_noise(self, image, cutoff=30, filter_type='gaussian'):"""去除图像噪声:param image: 输入图像:param cutoff: 截止频率:param filter_type: 滤波器类型 ('ideal'或'gaussian'):return: 去噪后的图像"""fshift = self.fft(image)if filter_type == 'ideal':filtered_fshift = self.ideal_low_pass(fshift, cutoff)else:filtered_fshift = self.gaussian_low_pass(fshift, cutoff)return self.ifft(filtered_fshift)def extract_edges(self, image, cutoff=10):"""提取图像边缘:param image: 输入图像:param cutoff: 截止频率:return: 边缘图像"""fshift = self.fft(image)filtered_fshift = self.ideal_high_pass(fshift, cutoff)return self.ifft(filtered_fshift)def visualize_spectrum(self, image):"""可视化图像频谱:param image: 输入图像:return: 频谱图像"""fshift = self.fft(image)magnitude_spectrum = np.log(1 + np.abs(fshift))# 归一化到0-255范围magnitude_spectrum = cv2.normalize(magnitude_spectrum, None, 0, 255, cv2.NORM_MINMAX)return magnitude_spectrum.astype(np.uint8)

使用示例:

# 使用示例
if __name__ == "__main__":# 读取图像image_path = "noise_image.png"image = cv2.imread(image_path, 0)  # 以灰度模式读取# 创建处理器实例processor = FrequencyImageProcessor()# 去除噪声denoised = processor.remove_noise(image, cutoff=30, filter_type='gaussian')# 提取边缘edges = processor.extract_edges(denoised, cutoff=10)# 可视化频谱spectrum = processor.visualize_spectrum(image)# 显示结果plt.figure(figsize=(12, 8))plt.subplot(221), plt.imshow(image, cmap='gray')plt.title('原始噪声图像'), plt.xticks([]), plt.yticks([])plt.subplot(222), plt.imshow(spectrum, cmap='gray')plt.title('频谱图'), plt.xticks([]), plt.yticks([])plt.subplot(223), plt.imshow(denoised, cmap='gray')plt.title('去噪后图像'), plt.xticks([]), plt.yticks([])plt.subplot(224), plt.imshow(edges, cmap='gray')plt.title('边缘图像'), plt.xticks([]), plt.yticks([])plt.tight_layout()plt.show()

📝 实践建议

  1. 从简单图像开始实验,逐步过渡到复杂图像
  2. 保存中间结果,便于比较不同参数的效果
  3. 尝试不同截止频率,找到最适合当前图像的参数
  4. 记录处理前后的图像差异,培养对频域处理的直觉

9.4 结语

傅里叶变换是图像处理中的基础且强大的工具,它让我们能以全新的视角观察和处理图像。无论是初学者还是专业人士,掌握频域处理技术都能让你的图像处理能力更上一层楼。

希望本文对你学习图像处理有所帮助!如有疑问或建议,欢迎在评论区留言讨论。祝你的图像处理之旅愉快而充实!


🎁 福利时间! 我已将本文所有代码整理成一个完整的Python包,包含更多实用功能和详细注释,欢迎在评论区留言获取下载链接!

相关文章:

傅里叶变换实战:图像去噪与边缘提取

傅里叶变换在图像处理中的应用与实践详解&#xff08;超详细教程实战代码&#xff09; &#x1f680; 本文从零开始详解傅里叶变换在图像处理中的应用&#xff0c;手把手教你实现图像去噪与边缘提取&#xff01;全文配套Python代码&#xff0c;新手也能轻松上手&#xff01; 一…...

go-中间件的使用

中间件介绍 Gin框架允许开发者在处理请求的过程中加入用户自己的钩子(Hook)函数这个钩子函数就是中间件&#xff0c;中间件适合处理一些公共的业务逻辑比如登录认证&#xff0c;权限校验&#xff0c;数据分页&#xff0c;记录日志&#xff0c;耗时统计 1.定义全局中间件 pac…...

昇腾NPU环境搭建

如果进入服务器输入npu-smi info可以看到npu情况&#xff0c;请直接跳转第三步 STEP1: 服务器安装依赖 sudo yum install -y gcc gcc-c make cmake unzip zlib-devel libffi-devel openssl-devel pciutils net-tools sqlite-devel lapack-devel gcc-gfortran python3-develyu…...

【HTML5学习笔记2】html标签(下)

1表格标签 1.1表格作用 显示数据 1.2基本语法 <table><tr> 一行<td>单元格1</td></tr> </table> 1.3表头单元格标签 表头单元格会加粗并且居中 <table><tr> 一行<th>单元格1</th></tr> </table&g…...

开源轻量级地图解决方案leaflet

Leaflet 地图&#xff1a;开源轻量级地图解决方案 Leaflet 是一个开源的 JavaScript 库&#xff0c;用于在网页中嵌入交互式地图。它以轻量级、灵活性和易用性著称&#xff0c;适用于需要快速集成地图功能的项目。以下是关于 Leaflet 的详细介绍和使用指南。 1. Leaflet 的核心…...

LLM学习笔记(六)线性代数

公式速查表 1. 向量与矩阵&#xff1a;表示、转换与知识存储的基础 向量表示 (Vectors): 语义的载体 在LLM中&#xff0c;向量 x ∈ R d \mathbf{x}\in\mathbb{R}^d x∈Rd 是信息的基本单元&#xff0c;承载着丰富的语义信息&#xff1a; 词嵌入向量 (Word Embeddings)&am…...

Vue 3.0双向数据绑定实现原理

Vue3 的数据双向绑定是通过响应式系统来实现的。相比于 Vue2&#xff0c;Vue3 在响应式系统上做了很多改进&#xff0c;主要使用了 Proxy 对象来替代原来的 Object.defineProperty。本文将介绍 Vue3 数据双向绑定的主要特点和实现方式。 1. 响应式系统 1.1. Proxy对象 Vue3 …...

Quasar组件 Carousel走马灯

通过对比两个q-carousel组件来&#xff0c;了解该组件的属性 官方文档请参阅&#xff1a;Carousel 预览 源代码 <template><div class"q-pa-md"><div class"q-gutter-md"><q-carouselv-model"slide"transition-prev&quo…...

Vue 2.0学习

个人简介 &#x1f468;‍&#x1f4bb;‍个人主页&#xff1a; 魔术师 &#x1f4d6;学习方向&#xff1a; 主攻前端方向&#xff0c;正逐渐往全栈发展 &#x1f6b4;个人状态&#xff1a; 研发工程师&#xff0c;现效力于政务服务网事业 &#x1f1e8;&#x1f1f3;人生格言&…...

LangFlow技术深度解析:可视化编排LangChain应用的新范式 -(3)组件系统

Component System | langflow-ai/langflow | DeepWiki 组件系统 相关源文件 组件系统是核心基础设施&#xff0c;使 Langflow 能够在工作流中创建、配置和连接模块化构建块。该系统通过为组件提供一致的接口来定义其输入、输出、执行行为以及与其他组件的连接&#xff0c;从…...

【Win32 API】 lstrcmpA()

作用 比较两个字符字符串&#xff08;比较区分大小写&#xff09;。 lstrcmp 函数通过从第一个字符开始检查&#xff0c;若相等&#xff0c;则检查下一个&#xff0c;直到找到不相等或到达字符串的末尾。 函数 int lstrcmpA(LPCSTR lpString1, LPCSTR lpString2); 参数 lpStr…...

LabVIEW光谱检测系统

腔衰荡光谱技术&#xff08;CRDS&#xff09;凭借高精度和高灵敏度特性&#xff0c;成为微量气体浓度检测的常用方法&#xff0c;而准确获取衰荡时间是该技术应用的关键。基于LabVIEW平台设计腔衰荡信号在线处理系统&#xff0c;实现对衰荡信号的实时采集、平均、拟合、显示和保…...

深入解读WPDRRC信息安全模型:构建中国特色的信息安全防护体系

目录 前言1 WPDRRC模型概述2 模型结构详解2.1 预警&#xff08;Warning&#xff09;2.2 保护&#xff08;Protect&#xff09;2.3 检测&#xff08;Detect&#xff09;2.4 响应&#xff08;React&#xff09;2.5 恢复&#xff08;Restore&#xff09;2.6 反击&#xff08;Count…...

uniapp-商城-59-后台 新增商品(属性的选中,进行过滤展示,filter,some,every和map)

前面讲了属性的添加&#xff0c;添加完成后&#xff0c;数据库中已经存在数据了&#xff0c;这时再继续商品的添加时&#xff0c;就可以进行属性的选择了。 在商品添加过程中&#xff0c;属性选择是一个关键步骤。首先&#xff0c;界面需要展示嵌套的属性数据&#xff0c;用户通…...

RDIFramework.NET Web敏捷开发框架 V6.2发布(.NET6+、Framework双引擎)

1、框架介绍 .NET6、Framework双引擎、全网唯一 RDIFramework.NET敏捷开发框架&#xff0c;是我司重磅推出的支持.NET6和.NET Framework双引擎的快速信息化系统开发、整合框架&#xff0c;为企业快速构建企业级的应用提供了强大支持。 依托框架强大的基座&#xff0c;开发人员只…...

JMeter 教程:编写 GET 请求脚本访问百度首页

目录 练习要求&#xff1a; 练习步骤&#xff1a; 效果图&#xff1a; 练习要求&#xff1a; 练习步骤&#xff1a; 效果图&#xff1a;...

JSP 实现二级联动下拉菜单:一次加载,前端动态更新

在Web开发中,二级联动下拉菜单(或多级联动)是一种非常常见的用户交互形式,例如选择省份后动态加载对应的城市列表。本文将详细介绍一种在JSP中实现二级联动的方法:后端一次性将所有联动数据加载到前端,然后通过JavaScript在客户端动态更新二级下拉菜单。这种方法对于数据…...

Room数据库

Room数据库 Room是Android Jetpack组件中的一款SQLite数据库抽象层框架&#xff0c;旨在简化本地数据库操作&#xff0c;提供编译时SQL校验、类型与安全、与LiveData/Flow无缝集成等特性。 1. 什么是Room 定义&#xff1a; Room 是 Android Jetpack 提供的一个 ORM&#xff…...

文件上传Ⅲ

#文件-解析方案-执行权限&解码还原 1、执行权限 文件上传后存储目录不给执行权限&#xff08;即它并不限制你上传文件的类型&#xff0c;但不会让相应存有后门代码的PHP文件执行&#xff0c;但是PNG图片是可以访问的&#xff09; 2、解码还原 数据做存储&#xff0c;解…...

前端取经路——量子UI:响应式交互新范式

嘿&#xff0c;老铁们好啊&#xff01;我是老十三&#xff0c;一枚普通的前端切图仔&#xff08;不&#xff0c;开玩笑的&#xff0c;我是正经开发&#xff09;。最近前端技术简直跟坐火箭一样&#xff0c;飞速发展&#xff01;今天我就跟大家唠唠从状态管理到实时渲染&#xf…...

15 C 语言字符类型详解:转义字符、格式化输出、字符类型本质、ASCII 码编程实战、最值宏汇总

1 字符类型概述 在 C 语言中&#xff0c;字符类型 char 用于表示单个字符&#xff0c;例如一个数字、一个字母或一个符号。 char 类型的字面量是用单引号括起来的单个字符&#xff0c;例如 A、5 或 #。 当需要表示多个字符组成的序列时&#xff0c;就涉及到了字符串。在 C 语言…...

AlphaEvolve:LLM驱动的算法进化革命与科学发现新范式

AlphaEvolve&#xff1a;LLM驱动的算法进化革命与科学发现新范式 本文聚焦Google DeepMind最新发布的AlphaEvolve&#xff0c;探讨其如何通过LLM与进化算法的结合&#xff0c;在数学难题突破、计算基础设施优化等领域实现革命性进展。从48次乘法优化44矩阵相乘到数据中心资源利…...

比较文本搜索策略 pgsearch、tsvector 和外部引擎

大家好&#xff0c;这里是架构资源栈&#xff01;点击上方关注&#xff0c;添加“星标”&#xff0c;一起学习大厂前沿架构&#xff01; 在应用程序中实现搜索功能时&#xff0c;您需要选择合适的文本搜索方法。本指南比较了 PostgreSQL 的内置搜索引擎tsvector、pg_search扩展…...

58. 区间和

题目链接&#xff1a; 58. 区间和 题目描述&#xff1a; 给定一个整数数组 Array&#xff0c;请计算该数组在每个指定区间内元素的总和。 输入描述 第一行输入为整数数组 Array 的长度 n&#xff0c;接下来 n 行&#xff0c;每行一个整数&#xff0c;表示数组的元素。随后…...

MySQL中表的增删改查(CRUD)

一.在表中增加数据&#xff08;Create&#xff09; INSERT [INTO] TB_NAME [(COLUMN1,COLUMN2,...)] VALUES (value_list1),(value_list2),...;into可以省略可仅选择部分列选择插入&#xff0c;column即选择的列&#xff0c; 如图例可以选择仅在valuelist中插入age和id如果不指…...

SQL练习(6/81)

目录 1.寻找连续值 方法一&#xff1a;使用自连接&#xff08;Self-Join&#xff09; 方法二&#xff1a;使用窗口函数&#xff08;Window Functions&#xff09; 2.寻找有重复的值 GROUP BY子句 HAVING子句 常用聚合函数&#xff1a; 3.找不存在某属性的值 not in no…...

Android 中 打开文件选择器(ACTION_OPEN_DOCUMENT )

在 Android 中&#xff0c;打开文件选择器&#xff08;File Picker&#xff09;通常是指启动一个系统提供的界面&#xff0c;让用户可以选择存储在设备上的文件。可以通过发送一个带有 Intent.ACTION_OPEN_DOCUMENT 或 Intent.ACTION_GET_CONTENT 的 Intent 来实现。 1、启动文…...

AWS中国区CloudFront证书管理和应用指南

在AWS中国区使用CloudFront时,SSL/TLS证书的管理和应用是一个重要的环节。本文将详细介绍如何在AWS中国区上传、管理和应用SSL证书到CloudFront分配。 1. 准备证书文件 首先,我们需要准备好SSL证书相关的文件。通常,这包括: 私钥文件(.key)公钥证书文件(.crt)证书链文…...

Python之三大基本库——Matplotlib

好久没来总结了&#xff0c;今天刚好有时间&#xff0c;我们来继续总结一下python中的matplotlib 一、什么是Matplotlib ‌Matplotlib‌是一个Python的2D绘图库&#xff0c;主要用于将数据绘制成各种图表&#xff0c;如折线图、柱状图、散点图、直方图、饼图等。它以各种硬拷贝…...

随笔:hhhhh

第一题 ∫ − ∞ ∞ x e x − e x d x ∫ 0 ∞ ln ⁡ t ⋅ e ln ⁡ t − t ⋅ 1 t d t ∫ 0 ∞ ln ⁡ t ⋅ e − t ⋅ 1 t ⋅ t d t ∫ 0 ∞ ln ⁡ t ⋅ e − t d t ψ ( 1 ) − γ \begin{align*} \int_{-\infty}^{\infty}xe^{x-e^x}\text{d}x&\int_{0}^{\infty}…...

计算机网络-----6分层结构

目录 “分层” 的设计思想&#xff1a; 计算机网络要完成的功能&#xff1a; 计算机网络的分层结构&#xff1a; 网络体系结构的概念&#xff1a; 各层之间的关系&#xff1a; 数据的传输过程 水平视角&#xff1a; 垂直视角&#xff1a; 相关概念 协议三要素&#x…...

初识SOC:RK3588

目录 一、高性能计算与边缘计算 二、多媒体处理与显示 三、图形与游戏开发 四、物联网与嵌入式系统 五、操作系统兼容性 RK3588作为瑞芯微推出的高性能处理器&#xff0c;凭借其多核架构、高算力NPU和多媒体处理能力&#xff0c;可广泛应用于以下领域&#xff1a; 一、高…...

卡顿检测与 Choreographer 原理

一、卡顿检测的原理 卡顿的本质是主线程&#xff08;UI 线程&#xff09;未能及时完成某帧的渲染任务&#xff08;超过 16.6ms&#xff0c;以 60Hz 屏幕为例&#xff09;&#xff0c;导致丢帧&#xff08;Frame Drop&#xff09;。检测卡顿的核心思路是监控主线程任务的执行时…...

第十天——贪心算法——深度总结

文章目录 贪心算法深度解析&#xff1a;原理与应用 1. 贪心算法的基本原理 1.1 贪心选择性质 1.2 最优子结构 1.3 贪心算法与动态规划的对比 2. 贪心算法的应用场景 3. 具体应用案例 3.1 分配饼干 (Assign Cookies) 3.2 分糖果 (Candy Distribution) 3.3 种花问题 (C…...

python自学笔记2 数据类型

字符串操作 f字符串&#xff1a; for index, char in enumerate(greeting_str):print(f"字符&#xff1a;{char}, 索引&#xff1a;{index}")f字符串可以方便的在字符串中插入变量 字符串切片 指定步长&#xff1a; print(greeting_str[::2])指定步长为2的取字符…...

nacos配置文件快速部署另一种方法

提交nacos配置的另一种一种方法,批命令/shell: 以下脚本直接把当前目录下的所有yaml文件一键提交到nacos上 前提是要先安装curl 以及 jq 然后 把下面的shell保存为 import-all.sh 然后 chmod x import-all.sh && ./import-all.sh 就好了. 记得修改一下的NAMESPACE_…...

RTK哪个品牌好?2025年RTK主流品牌深度解析

在测绘领域&#xff0c;RTK 技术的发展日新月异&#xff0c;选择一款性能卓越、稳定可靠的 RTK 设备至关重要。2025 年&#xff0c;市场上涌现出众多优秀品牌&#xff0c;本文将深入解析几大主流品牌的核心竞争力。 华测导航&#xff08;CHCNAV&#xff09;&#xff1a;技术创…...

游戏引擎学习第285天:“Traversables 的事务性占用”

回顾并为当天的工作做准备 我们有一个关于玩家移动的概念&#xff0c;玩家可以在点之间移动&#xff0c;而且当这些点移动时&#xff0c;玩家会随之移动。现在这个部分基本上已经在工作了。我们本来想实现的一个功能是&#xff1a;当玩家移动到某个点时&#xff0c;这个点能“…...

HNUST湖南科技大学-安卓Android期中复习

使用说明&#xff1a;除了选择判断就看习题外&#xff0c;推荐重点复习三四章多复习案例&#xff0c;这里应该是编程空题&#xff0c;把界面控件、活动单元熟悉一下。第五章&#xff08;数据存储方式&#xff0c;尤其是文件存储&#xff09;、第六章&#xff08;重点内容提供者…...

一种应用非常广泛的开源RTOS(实时操作系统):nuttx

什么是NuttX&#xff1f; NuttX&#xff08;读音接近“纳特-艾克斯”&#xff09;是一种应用非常广泛的开源RTOS&#xff08;实时操作系统&#xff09;&#xff0c;由Gregory Nutt博士主要推动开发。RTOS&#xff0c;即 Real-Time Operating System&#xff0c;直译为“实时操…...

WebSocket 客户端 DLL 模块设计说明(基于 WebSocket++ + Boost.Asio)

WebSocket 客户端 DLL 模块设计说明&#xff08;基于 WebSocket Boost.Asio&#xff09; &#x1f4cc; 目录 一、模块总览二、导出接口说明&#xff08;EXPORTS&#xff09;三、状态变量功能解读四、连接启动流程详解五、事件回调说明六、消息发送流程七、心跳与断连 JSON …...

微信小程序:封装request请求、解决请求路径问题

一、创建文件 1、创建请求文件 创建工具类文件request.js,目的是用于发送请求 二、js接口封装 1、写入接口路径 创建一个变量BASE_URL专门存储api请求地址 2、获取全局的token变量 从缓存中取出token的数据 3、执行请求 (1)方法中接收传递的参数 function request(url,…...

Ubuntu24.04 安装 5080显卡驱动以及cuda

前言 之前使用Ubuntu22.04版本一直报错,然后换了24.04版本才能正常安装 一. 配置基础环境 Linux系统进行环境开发环境配置-CSDN博客 二. 安装显卡驱动 1.安装驱动 按以下步骤来&#xff1a; sudo apt update && sudo apt upgrade -y#下载最新内核并安装 sudo add…...

Jenkins的流水线执行shell脚本执行jar命令后项目未启动未输出日志问题处理

现象 在流水线里配置了启动脚本例如&#xff0c;nohup java -jar xxx.jar >nohup.out 2>&1 & 但是在服务器发现服务并未启动,且nohup日志里没输出日志,这样的原因是jenkins在执行完脚本后&#xff0c;就退出了这个进程。 解决 在启动脚本执行jar命令的上一步…...

Core Web Vitals 全链路优化:从浏览器引擎到网络协议深度调优

Core Web Vitals 全链路优化:从浏览器引擎到网络协议深度调优 一、浏览器渲染引擎级优化 1.1 合成器线程优化策略 • 分层加速:通过will-change属性创建独立的合成层 .accelerated {will-change: transform;backface-visibility: hidden; }• 光栅化策略调整:使用image-r…...

【网络编程】十、详解 UDP 协议

文章目录 Ⅰ. 传输层概述1、进程之间的通信2、再谈端口号端口号的引出五元组标识一个通信端口号范围划分常见的知名端口号查看知名端口号协议号 VS 端口号 3、两个问题一个端口号是否可以被多个进程绑定&#xff1f;一个进程是否可以绑定多个端口号&#xff1f; 4、部分常见指令…...

求职困境:开发、AI、运维、自动化

文章目录 问&#xff1a;我的技术栈是web全栈&#xff08;js&#xff0c;css&#xff0c;html&#xff0c;react&#xff0c;typscript&#xff09;&#xff0c;C开发&#xff0c;python开发&#xff0c;音视频图像开发&#xff0c;神经网络深度学习开发&#xff0c;运维&#…...

如何将数据从一部手机传输到另一部手机 | 5 种便捷传输方式

更换新手机可能是一种令人兴奋的体验&#xff0c;但您仍然需要解决问题 - 如何将数据从一部手机传输到另一部手机。幸运的是&#xff0c;有多种方法可以简化此过程&#xff0c;从一键式解决方案到基于云的传输。本文探讨了五种流行的技术来帮助您无缝迁移数据。 第 1 部分&…...

GEE计算 RSEI(遥感生态指数)

&#x1f6f0;️ 什么是 RSEI&#xff1f;为什么要用它评估生态环境&#xff1f; RSEI&#xff08;遥感生态指数&#xff0c;Remote Sensing Ecological Index&#xff09; 是一种通过遥感数据计算得到的、综合反映区域生态环境质量的指标体系。 它的设计初衷是用最少的变量&…...

k8s监控方案实践补充(二):使用kube-state-metrics获取资源状态指标

k8s监控方案实践补充&#xff08;二&#xff09;&#xff1a;使用kube-state-metrics获取资源状态指标 文章目录 k8s监控方案实践补充&#xff08;二&#xff09;&#xff1a;使用kube-state-metrics获取资源状态指标一、Metrics Server简介二、kube-state-metrics实战部署1. 创…...