OpenCV图像傅里叶变换实战:频谱可视化与频率域滤波
傅里叶变换这玩意儿上学的时候信号与系统课里被那一堆公式折磨得死去活来当时就一个想法这玩意儿除了考试到底还能干啥结果工作之后玩OpenCV发现图像处理里到处是它的影子什么去噪、增强、压缩底层全是DFT。尤其是刚接触OpenCV那会儿我用cv2.dft跑出一张频谱图黑乎乎一片中间一个亮十字完全看不懂是什么鬼调了半天参数也没搞明白那些白点意味着什么。后来才慢慢悟过来这玩意儿其实就是把一张图从空间域换到频率域去重新观察就像你把一段音乐从波形图切到频谱图看到的完全是另一个维度的信息。这篇文章我不打算跟你复述教材上的公式推导那些东西网上铺天盖地看得人头大。我就从一个实践者的角度讲讲图像傅里叶变换DFT在OpenCV里到底怎么用、每一步为啥要这么写、踩过哪些坑以及怎么用它做最简单的频率域滤波。适合刚入门OpenCV、对频域概念一知半解的读者也适合那些想系统梳理一遍DFT实操细节的朋友。1. 图像傅里叶变换到底在讲什么先把一个最容易绕晕的概念掰扯清楚图像是一个二维信号傅里叶变换就是把这张图像从空间域转到频率域。空间域里每个像素点表示“这个位置的亮度是多少”频率域里每个点表示“这个频率的分量有多强”。听不懂没关系换个生活化的类比你面前有一块花布空间域描述的是“哪个位置是什么颜色”频率域描述的是“这块布上的花纹整体上由哪些粗细、疏密的条纹叠加而成”。图像里的低频分量对应灰度变化平缓的区域比如天空、墙壁、背景大色块高频分量对应灰度变化剧烈的地方比如边缘、纹理、噪点。这解释了为啥很多去噪算法都从频域入手——噪声通常集中在高频段把人眼不太敏感的高频成分削掉一部分视觉上画质变化不大但噪声明显减轻。DFT是离散傅里叶变换因为计算机只能处理离散数据。对一张尺寸为M×N的图像做DFT得到的结果也是一个M×N的复数矩阵。每个位置(u,v)的复数取值幅值表示该频率分量的能量大小相位表示该分量的位置信息。很多人只盯着幅值看频谱图忽略了相位但相位在图像重建里非常关键——把两张图的幅值和相位互换再重建你会看到图像内容基本由相位决定。OpenCV里做DFT不需要自己写公式cv2.dft函数一行就能搞定。但它的返回值和很多人的直觉不一样返回的不是一个干净的幅值矩阵而是一个双通道的复数数组——通道0保存实部通道1保存虚部。这是学习DFT实操时第一个要接受的事实你必须自己动手去算幅值、相位再映射到0到255的范围才能显示成图像。这个“数值到可视化”的过程是一道经典坎。很多人直接打印dft结果发现全是大数值和小数值混在一起根本没法看就是因为漏掉了三个关键步骤取幅值、对数缩放、归一化。后面我会逐个拆解。2. OpenCV中dft函数的使用要点cv2.dft的完整签名是cv2.dft(src, flags0, nonzeroRows0)。src必须是浮点型单通道或双通道图像通常我们会先把图像转成float32再传进去。flags是核心常用的有DFT_COMPLEX_OUTPUT和DFT_REAL_OUTPUT前者用于正向变换输入实数输出复数后者用于逆变换输入复数输出实数。有一点要注意OpenCV的dft默认输出格式是“紧凑型”的也就是说结果里左上角是低频分量四个角被折叠到边缘。大多数教材里的频谱图都是中心化之后的——低频在中间高频在四周这样看起来更直观。OpenCV没有直接提供的fftshift函数但这一步可以自己手写把图像按水平和垂直方向各切一半交换象限就行。既然是复数结果肯定要有个地方存。OpenCV里可以用cv2.merge把实部虚部合成为双通道Mat也可以直接把dft的输出当成有两个通道的Mat来用。cv2.magnitude函数接收两个单通道Mat返回幅值正是我们需要的。这里有个细节牵扯性能cv2.magnitude内部会对每个元素做开方和平方操作对大图来说有一定耗时但比逐像素用Python循环快了好几个数量级。如果你处理的是超大图像cv2.getOptimalDFTSize这个函数值得了解。DFT的计算效率跟尺寸的质因数分解有关当尺寸是2、3、5的幂次乘积时速度最快。这个函数会返回不小于原尺寸的最优尺寸你可以用cv2.copyMakeBorder先把图像pad到最优尺寸算完再裁剪回来。我实测过一张4000×3000的图像优化前后耗时能差好几倍不是玄学是算法本身的特性决定。再说一个容易搞混的操作名称很多人拿到频谱图看到中心亮、四周暗想用cv2.dft直接做逆变换却发现结果不对。这是因为你需要先做中心化逆操作把低频移回左上角然后调用cv2.dft并传入DFT_INVERSE|DFT_REAL_OUTPUT才能得到正确的空间域图像。忘了去中心化重建结果就是四块镜像拼图我第一次踩这个坑时盯着输出怀疑了半天人生。下表汇总了这几个常用flag的含义方便对照标志位作用应用场景DFT_COMPLEX_OUTPUT实数输入输出双通道复数正向DFTDFT_REAL_OUTPUT复数输入输出单通道实数逆DFTDFT_INVERSE执行逆变换频域处理后的空间域重建DFT_SCALE把结果除以元素总数配合逆变换做归一化注意DFT_SCALE是给逆变换用的因为正向DFT的结果通常不做归一化直接逆变换回来数值会放大N倍除以M×N才还原。3. 完整实操从读取图像到频谱可视化先跑通一条最简单的链路读取一张灰度图 → 转float32 → 做DFT → 计算幅值 → 对数缩放 → 中心化 → 归一化显示。代码不长但每一步都有讲究。import cv2 import numpy as np import matplotlib.pyplot as plt # 读图并转灰度 img cv2.imread(test.jpg, cv2.IMREAD_GRAYSCALE) # 转float32因为dft要求浮点输入 img_float np.float32(img) # 正向DFT输出双通道复数 dft cv2.dft(img_float, flagscv2.DFT_COMPLEX_OUTPUT) # 拆分实部虚部计算幅值 dft_real, dft_imag cv2.split(dft) magnitude cv2.magnitude(dft_real, dft_imag)这一步得到的magnitude数值范围很大最小可能是0最大可能是几十万甚至上百万。直接当图像显示全屏几乎都是黑的因为少数极大值把显示范围彻底拉伸了。标准做法是先做对数变换压一下动态范围magnitude_log np.log(1 magnitude)。加1是因为log(0)没意义也能保证最小值是0不会出现负无穷。接下来中心化。前面说了OpenCV的dft输出是四角低频需要把象限交换一下让低频移到中心。我习惯自己写一个shift函数用切片交换四个象限def fftshift(img): # 适用于OpenCV风格的中心化 rows, cols img.shape[:2] crow, ccol rows // 2, cols // 2 # 四个象限交换 # 左上 - 右下右下 - 左上右上 - 左下左下 - 右上 swapped np.zeros_like(img) swapped[:crow, :ccol] img[crow:, ccol:] swapped[crow:, ccol:] img[:crow, :ccol] swapped[:crow, ccol:] img[crow:, :ccol] swapped[crow:, :ccol] img[:crow, ccol:] return swapped把magnitude_log经过fftshift处理后用cv2.normalize归一到0-255范围再转成uint8就能用matplotlib或OpenCV显示频谱图了。magnitude_shift fftshift(magnitude_log) magnitude_norm cv2.normalize(magnitude_shift, None, 0, 255, cv2.NORM_MINMAX) magnitude_disp np.uint8(magnitude_norm) plt.imshow(magnitude_disp, cmapgray) plt.title(Spectrum after shift and log) plt.show()跑完你就能看到一张典型的频谱图中心是个十字亮线两侧对称分布着一些亮点。竖直的亮线对应原图中水平方向上的纹理水平的亮线对应竖直方向上的纹理。如果原图里有一条明显的斜向线条频谱里也会有一对对称的亮斑方向与之垂直。这些亮斑的位置和亮度就是对图像结构最直观的频率描述。有一个很常见的困惑为什么矩形图像做DFT后频谱图中心总有个十字亮线其实那不是图像本身的内容而是图像边界的不连续造成的。图像四周的像素值骤变到一个不存在的区域DFT会把这种突变当成高通特征于是横竖两条亮线就出来了。这是边界效应不是bug。4. 基于DFT的频率域滤波实战频谱图拿到手了不拿来做点正事就太可惜了。频率域滤波的基本思路是对频谱中心化后构造一个和频谱同尺寸的滤波器掩膜让想要的频率成分通过、挡住不想要的然后用掩膜乘上复数频谱再做逆变换回空间域。注意是在复数域逐元素相乘不是乘幅值图新手在这容易搞混——拿幅值图像去乘相位信息就丢了重建出来的图会面目全非。先看低通滤波。低通就是保留中心低频区域、抹掉四周高频。玩法很简单生成一个和原图尺寸一样的Mat中心一个圆盘区域填1其他地方填0。圆盘半径决定截止频率半径越大保留的高频越多图像越清晰但去噪效果弱半径越小图像越平滑模糊。# 假设已得到中心化后的dft_shift仍然保持双通道复数结构 rows, cols img.shape[:2] crow, ccol rows // 2, cols // 2 # 构造低通掩膜半径30的圆形 mask_low np.zeros((rows, cols, 2), np.float32) cv2.circle(mask_low, (ccol, crow), 30, (1, 1), -1) # 复数频谱逐元素乘掩膜 dft_filtered dft_shift * mask_low # 去中心化并做逆变换 dft_ishift fftshift(dft_filtered) img_back cv2.dft(dft_ishift, flagscv2.DFT_INVERSE cv2.DFT_REAL_OUTPUT) img_back np.clip(img_back, 0, 255).astype(np.uint8)这里有个细节cv2.dft的逆变换输出是float32像素值范围理论上跟原图一致但实际计算过程中可能会出现负值或超过255的值所以np.clip必不可少。如果你不放心数值可以先做img_back cv2.normalize(img_back, None, 0, 255, cv2.NORM_MINMAX)再转uint8不过这样会改变图像整体亮度对比度有时候反而不好看简单clip通常更保真。高通滤波和低通的掩膜正好相反圆形区域中心为0外部为1保留高频边缘纹理去掉低频平缓区域。结果是边缘被提取出来大片平坦区域变成接近中等的灰色。把高通滤波后加上原图还能实现简单的锐化效果——边缘增强但不太破坏原图亮度结构。再看一个实用技巧陷波滤波。如果图像里有周期性噪声比如扫描纹路、条纹干扰在频谱图上你会看到对称于中心的一对亮斑——它们就是噪声的频率。把这些亮斑区域用零掩膜抠掉再逆变换回来周期性噪声就没了图像主要结构几乎不受影响。这个操作在空间域做非常麻烦频域一刀下去就解决是DFT最典型的应用场景之一。我之前处理过一类带水波纹纹理的扫描文档用了陷波滤波之后效果立竿见影速度比空间域各种智能去噪算法快得多。5. 常见问题与排查技巧实录实践过程中我总结了一些高频问题整理成一个速查表每个都是真实踩过的坑现象原因解法频谱图全黑/只有中心一个亮点忘了做对数缩放动态范围被极大值压制用np.log(1 magnitude)频谱图出现明显的竖/横十字线矩形图像边界不连续常见正常现象可先对图像做边界扩展或用窗函数预处理结果图像出现大量黑白棋盘格逆变换前忘了去中心化逆变换前先把四象限换回去重建图像数值很大整体过暗或过亮逆变换缺DFT_SCALE或没clip用DFT_INVERSE DFT_SCALE输出后clipdft处理大图特别慢尺寸包含大质因数getOptimalDFTSizecopyMakeBorder预填充滤波后图像边缘发灰/模糊异常掩膜边缘没有平滑过渡振铃效应用渐变掩膜替代硬边缘第二条多说一句十字线其实可以缓解。方法是对原图先乘一个窗函数比如Hamming窗或Hann窗让图像边界平滑降到0再做DFT。这样十字线会明显减弱代价是图像边缘区域的信息也被稍微压暗。绝大多数场景不处理也能接受毕竟我们一般看频谱图只是为了分析主要频率分量。第五条对性能的影响很大补充一个具体示例假设原图是1920×1080这个尺寸分解质因子是2^6×3×5×3还有不少小因子dft速度还行。但如果尺寸是1922×1082质因数分解后包含大质数DFT速度会骤降。getOptimalDFTSize会返回例如1920或2048这样的尺寸再用copyMakeBorder把图pad过去能显著提速。处理视频帧时这个优化尤其值得因为每帧都要算一次累积下来能省不少时间。还有一个很多人忽视的问题图像是彩色图时怎么用DFT一般做法是拆成B、G、R三个通道分别做DFT分别滤波再合并或者先转YCrCb只处理亮度通道。直接对三通道彩色图调用dftOpenCV会当成多通道独立处理出来的结果你需要逐通道拆分操作比较绕。我个人习惯是只对灰度做频域处理需要彩色输出时再把处理后的亮度通道和原色度通道合回去这样效率高、伪影少。关于振铃效应再展开说几句。滤波器掩膜如果是硬边界比如圆内全1、圆外全0在频率域相当于给频谱加了个矩形窗逆变换后图像在边缘附近会出现明暗交替的波纹看起来像“回声”这就是振铃。缓解办法是用平滑过渡的掩膜可以用cv2.GaussianBlur对掩膜做个模糊或直接构造渐变半径的掩膜。比如低通掩膜用(dist r)判断之外再加一段过渡带(r dist r5)的中间值。这样滤波结果更自然边缘不会出现那种诡异的光环。# 自带渐变过渡的低通掩膜示例 y np.arange(rows).reshape(-1, 1) x np.arange(cols).reshape(1, -1) dist np.sqrt((x - ccol)**2 (y - crow)**2) mask_low_smooth np.clip(r 10 - dist, 0, 1) / 10 mask_low_smooth mask_low_smooth[..., np.newaxis].astype(np.float32)这段代码的想法很简单距离中心越远权重从1线性降到0而不是直接跳变。6. 一点实战体会与扩展思路多说几句个人体会。刚开始用OpenCV的dft时我一度陷入一个误区以为频谱图亮度越高的地方就是图像里最重要的内容。其实不然幅值只代表“这个频率成分有多强”但很多重要信息尤其是边缘位置藏在相位里。只看幅值滤波重建出的图像可能整体结构还在但细节位置会漂移。这也是为什么频率域滤波不适合大尺度盲目操作的原因——你无法精确控制对相位的破坏。在图像分类任务里也有人把频谱图当作另一种“特征图”和空间域特征做融合这种做法在一些纹理识别、缺陷检测的小数据集上有奇效。把原图做DFT得到幅值图和原图一起送入卷积网络让模型自己学两个域的信息如何结合。我自己试过在工业表面缺陷检测的场景下融合频谱特征后准确率提升不算夸张但在某些瑕疵和不规则纹理的分离上确实比单看空间域稳定不少。这种领域化的玩法算是把DFT从“教科书概念”变成了“实用工具箱”的另一种姿势。另外OpenCV还有个cv2.dct离散余弦变换它是DFT的亲戚输出是实数没有复数域那一堆拆分合并的麻烦。JPEG压缩的核心就是DCT。如果你只是在做图像压缩、去块效应之类的任务DCT往往比DFT更顺手。DFT真正的优势在于频率分析、周期噪声去除、滤波丢相位不敏感的场景以及需要看全频率分布的时候。最后给个建议对着一个棋盘格、一个人像、一张带周期噪点的扫描图分别跑一遍DFT看看频谱图长什么样再去对比低通高通处理后的重建效果。这个动手过程比读十篇理论文章都管用。搞清楚频谱图上亮点的位置和内容之间的关系你才算真正把傅里叶变换这块骨头啃下来了以后再遇到跟频域相关的OpenCV任务都会有底气得多的那种感觉。

相关新闻

基于Spring Boot的高校科研信息管理系统设计与实现全解析

基于Spring Boot的高校科研信息管理系统设计与实现全解析

每年四五月份,总有一批人被高校科研管理系统这类选题折磨得睡不着觉。我接过不少类似的咨询和调试需求,从老师、研究生到本科毕设党,需求表单长得差不多:项目申报、中期检查、结题验收、论文登记、经费统计……看上去业务逻辑不复…

2026/10/12 4:29:41 阅读更多 →
跨模态行人重识别实战:对比学习与注意力差异建模复现指南

跨模态行人重识别实战:对比学习与注意力差异建模复现指南

1. 跨模态行人重识别的问题本质与方案定位跨模态行人重识别(Cross-Modality Person Re-identification,业内常简称为跨模态 ReID)要解决的核心问题很具体:同一名行人在可见光摄像头下被拍到一次,又在红外摄像头下被拍到…

2026/10/12 4:29:41 阅读更多 →
AI论文写作全流程指南:从选题到答辩的8个高效工具

AI论文写作全流程指南:从选题到答辩的8个高效工具

每年的四月到六月,我的聊天软件都会收到类似的消息:一个平时不怎么联系的同学突然冒出来,先是"在吗",然后是一句"论文还有救吗"。前几天凌晨,A同学直接把Word文档发过来,文件名是"…

2026/10/12 4:29:41 阅读更多 →

最新新闻

C语言整除判断:从取余运算到流程图与同余实战

C语言整除判断:从取余运算到流程图与同余实战

提到“整除”这两个字,写代码的人脑子里通常先闪过的是C语言里的%取余符。说实话,这个运算符用起来简单,但真要拿它去判断“一个数能不能同时被3和5整除”,再画一张标准流程图,很多人会卡在细节上。前几天一个读者给我…

2026/10/12 5:20:07 阅读更多 →
近五十年的围墙

近五十年的围墙

▲图注:这份采购文件里要修的东西,一样也不在机房的机柜里。华中某省的无线电台管理中心在2024年5月发布了一份竞争性磋商采购文件,为四个中波转播台做机房配套设施及围墙改造,总预算约300万元,分成四个包,…

2026/10/12 5:20:07 阅读更多 →
FATE 2.0 Hetero NN Pipeline 实战指南:基于 FedPass 与 SSHE 的纵向联邦神经网络

FATE 2.0 Hetero NN Pipeline 实战指南:基于 FedPass 与 SSHE 的纵向联邦神经网络

人工智能机器学习联邦学习深度学习分布式训练隐私计算密码学 【免费下载链接】FATE An Industrial Grade Federated Learning Framework 项目地址: https://gitcode.com/gh_mirrors/fa/FATE 点击查看 免费下载 导读 本文围绕 examples/pipeline/hetero_nn 目录下的…

2026/10/12 5:20:07 阅读更多 →
Agent框架工程化实战:全插件化架构与可回放会话日志设计

Agent框架工程化实战:全插件化架构与可回放会话日志设计

1. 从一次线上事故说起:为什么我要拆解这套 Agent 框架去年年底,我负责的一个智能体项目在生产环境里翻了一次车。现象很典型:用户反馈某类任务处理到一半就"卡死",日志里只留下一句模糊的超时提示,复现路径…

2026/10/12 5:20:07 阅读更多 →
采购如何证明自己价值?一套可量化的省钱核算体系实战指南

采购如何证明自己价值?一套可量化的省钱核算体系实战指南

采购就是给公司花钱的?这大概是采购行业最大的误解。你谈了三轮价格、换了两个供应商、顶住了销售端的紧急插单,年底一算给公司省了几十万,结果没人提;反过来原材料一涨价、供应商交期一延误,全公司都盯着采购说“你怎…

2026/10/12 5:20:07 阅读更多 →
UE5实战:从性能卡顿到线程安全的5大工程断面解析

UE5实战:从性能卡顿到线程安全的5大工程断面解析

1. 这不是教程,是我在三个UE项目里拆出来的引擎骨架“游戏引擎架构深度解析(五):UE实战与高级主题”——看到这个标题,别急着点开。我见过太多人把这类内容当成“进阶技巧合集”,结果学完还是写不出一个能稳…

2026/10/12 5:19:07 阅读更多 →

日新闻

复古胶片颗粒感噪点合成器:Canvas ImageData 像素高斯杂色注入算法

复古胶片颗粒感噪点合成器:Canvas ImageData 像素高斯杂色注入算法

在数码相机、高清显示屏与现代矢量图形技术高度发达的今天,画面可以做到绝对的锐利、平滑与无瑕。然而,当一张秋日手账插画或拍立得照片过于“平整无瑕”时,往往会散发出一种冰冷生硬的“数码塑料感(Digital Plasticity&#xff0…

2026/10/12 0:00:59 阅读更多 →
活字印刷古籍线装排版:Canvas 竖排文字与栏线自适应算法

活字印刷古籍线装排版:Canvas 竖排文字与栏线自适应算法

在现代网页与移动端设计中,横排(Horizontal Layout)早已经成为了绝对的主流。然而,当我们翻开泛黄的线装古籍、宋版木刻诗集,或是欣赏一张茶道雅集的手写便签时,那种**自上而下纵向书写、自右向左逐列铺展&…

2026/10/12 0:00:59 阅读更多 →
周日晚间的“精神松绑减震器”:无压力情绪倾倒箱与温和轻声陪伴

周日晚间的“精神松绑减震器”:无压力情绪倾倒箱与温和轻声陪伴

每到周日的晚上八点到十点,很多人心里都会悄悄亮起一盏警示灯。 在心理学上,这种现象有一个专门的称谓——“周日夜晚焦虑症(Sunday Scaries)”。明天又是周一,闹钟又要重新在七点响彻卧房;脑海里仿佛有一个…

2026/10/12 0:00:59 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/12 0:16:30 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/12 0:16:38 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/12 0:16:43 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/11 10:45:37 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/11 14:36:53 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/11 14:36:54 阅读更多 →