暗通道先验去雾算法:从物理原理到Python工程实现

发布时间:2026/9/16 3:20:59
暗通道先验去雾算法:从物理原理到Python工程实现 雾天拍的图后期怎么救回来这事我研究过不少时间。做计算机视觉图像增强相关的项目时最常遇到的就是雾霾导致对比度崩塌、色彩灰白的问题。直接用Photoshop拉对比度或者调白平衡效果都很生硬因为雾的影响不是简单的“画面变灰”而是一个有物理规律的图像退化过程。后来我系统地把何恺明那篇经典的暗通道先验去雾算法Dark Channel Prior, DCP读透又用Python从头到尾实现了一遍才真正理解这个算法为什么效果惊艳、又为什么有些场景会翻车。这篇文章把我踩过的坑、推导过的数学公式、完整的Python代码还有参数调优经验一次讲清楚适合计算机视觉课程的作业参考也适合想把DCP落地到实际项目的开发者。1. 为什么雾天拍出来的照片会让算法“失灵”1.1 雾天成像的老底大气散射模型先理解一个问题我们看到的雾天图像究竟是怎么形成的光从物体表面反射进入相机之前要穿越大气的介质层。雾天时大气中悬浮着大量微小水滴和颗粒物光线经过这些介质时会发生两部分变化一部分是物体反射的光被散射和吸收导致到达相机的有效光强衰减另一部分是环境光天空光、太阳光被散射进相机视线方向叠加在图像上形成一层乳白色的“雾罩”。这一物理过程用一个经典模型表达就是I(x) J(x) * t(x) A * (1 - t(x))其中各项的含义对应到实际场景里非常直观I(x)相机实际拍到的有雾图像像素值J(x)场景原本的清晰无雾图像也就是我们想要恢复的目标A全局大气光强度可以理解为无限远处天空的颜色亮度t(x)透射率表示物体反射光经过介质后有多少比例能到达相机。t(x)越小说明雾越浓。这个公式其实就是把拍摄到的图像看成两部分加权叠加一部分是清晰图像衰减后的结果另一部分是大气光的污染。去雾的本质就是从I(x)中反解出J(x)。但由于I和J都是未知的单一方程两个未知数这就是个典型的病态问题ill-posed problem。1.2 为什么直方图均衡化和白平衡救不了雾图很多初学者拿到雾图第一反应就是上直方图均衡化Histogram Equalization。它的思路是调整像素值的分布让动态范围铺满整个区间。直方图均衡化确实能在某些低对比度图像上取得立竿见影的效果但对雾图来说问题很大它做的是全局或者局部的像素重映射完全没考虑雾的浓度随深度变化的空间差异雾图中远处的物体透射率低近处的物体透射率高这种空间非均匀退化用统一的灰度映射无法建模均衡化会把大气光当成“高光”一起拉伸结果就是天空区域过曝、白茫茫一片更白远处依然雾蒙蒙近处反而过饱和。白平衡就更不用说了它只能纠正色偏对雾造成的对比度损失和深度相关的衰减基本无能为力。这也是暗通道先验最有价值的地方——它不是通过单纯的像素级操作去“猜”清晰图而是先基于一个统计规律估算出每个像素的透射率再反推无雾图像。它是建模物理过程不是做像素调整。2. 暗通道先验一个极其简单又反直觉的统计规律2.1 暗通道的数学定义“暗通道先验”这个名词听起来高深其实拆开来看就是一条统计规律。作者统计了大量户外无雾图像的局部区域后发现对于绝大多数无雾图像的任意局部小方块区域总存在至少一个颜色通道的某些像素其亮度值非常低趋近于零。把这个规律用数学语言写出来就是暗通道的定义J_dark(x) min_{y∈Ω(x)} ( min_{c∈{r,g,b}} J_c(y) ) → 0其中Ω(x)表示以像素x为中心的一个局部窗口c表示RGB三个颜色通道。一句话解释在每个小窗口里先取三通道的最小值形成一个灰度图再对这个灰度图做一次最小值滤波。得到的图就叫暗通道图。对于无雾的户外图像暗通道图的像素值应该极低接近0。2.2 为什么这个规律“反直觉”第一眼看到这个规律时很多人会觉得不对劲天空那么亮怎么可能每个窗口里都有暗像素关键在于这句“存在至少一个颜色通道的某些像素”它是存在性判断不是全图一致性判断。自然界中的物体只要是彩色的总会有饱和度高、反射率低的区域绿色树叶反射绿光红色通道的值自然很低红色花朵反射红光蓝色通道的值自然很低深色石头、阴影区域所有通道值都很低彩色建筑的彩色墙面上总有一个颜色通道不反射对应波长的光。所以局部窗口取三通道最小值大概率会得到一个很小的值。而这个规律在雾图中会被打破由于大气光的叠加所有通道的像素值都被抬高了暗通道不再接近0。这正是算法可以利用的核心信号——暗通道的“亮度”其实刻画了雾的浓度。2.3 暗通道先验的适用范围与失效场景这条统计规律是基于大量自然图像统计得出的先验肯定存在不适用的情况大面积天空区域天空在所有通道都是高亮的暗通道值不接近0白色物体、雪地、白墙整个窗口没有明显暗像素强光源区域如车灯、反光面局部窗口暗通道值也偏高。但即便是这些区域在实际应用时算法也不会完全失灵原因稍后会展开说。至少目前在学术界和工业界暗通道先验的统计可靠性已经被反复验证过是近十五年来图像去雾领域引用率最高、影响最大的工作之一。3. 从暗通道到去雾公式推导与参数设定3.1 联立方程反解透射率回到大气散射模型I(x) J(x) * t(x) A * (1 - t(x))现在要做的是想办法求出每个像素的透射率t(x)。这里就要把暗通道先验作为约束条件引进来。首先做归一化等式两边同时除以大气光AI_c(x) / A_c t(x) * J_c(x) / A_c (1 - t(x))这里下标c表示某个颜色通道。接下来做一个关键操作——对等式两边在局部窗口Ω(x)内先取各个通道的最小值再取三通道中的最小值min_{y∈Ω(x)} ( min_c ( I_c(y) / A_c ) ) t̃(x) * min_{y∈Ω(x)} ( min_c ( J_c(y) / A_c ) ) (1 - t̃(x))这里透射率在局部窗口内假设为常数所以可以直接提到min外面。然后利用暗通道先验J_c(y)的暗通道趋近0也就是min_{y∈Ω(x)} ( min_c ( J_c(y) / A_c ) ) → 0整理后就得到透射率的估计公式t̃(x) 1 - min_{y∈Ω(x)} ( min_c ( I_c(y) / A_c ) )看出来了吗右边这一项其实就是有雾图像的暗通道图除以大气光。雾越浓的区域暗通道越亮透射率估计值就越接近0符合直觉。3.2 大气光A如何估计大气光A的估计方法在原始论文中有非常明确的操作流程先计算有雾图像的暗通道图在暗通道图中找到亮度最高的前0.1%的像素位置回到原图中在这些位置对应的像素里取RGB三通道的最大值作为大气光A。这个设计的逻辑是暗通道最亮的像素通常是图像中最不透明的、雾最浓的区域比如远处的天空或远景这些区域受大气光影响最大其像素值最接近大气光强度。在具体实现时通常会取三个通道各自的最大值作为A_r、A_g、A_b得到一个三维向量。也可以取一个标量表示整体大气光强度但三维向量更保留颜色信息恢复出来的图像色偏更小。3.3 引入系数ω保留一点雾感更自然直接套用公式求出的t(x)恢复出来的图像往往过度增强显得不真实。因为暗通道先验本身是一个统计近似求得的透射率存在偏差。何恺明在论文中引入了一个0到1之间的系数ω修正透射率估计t(x) 1 - ω * min_{y∈Ω(x)} ( min_c ( I_c(y) / A_c ) )ω的典型取值为0.95。它的作用是在去雾效果和自然度之间取一个平衡——保留少量雾感避免“用力过猛”导致图像发暗、颜色失真。你如果拿0.9、0.95、1.0三组参数分别跑一遍会发现1.0的结果确实更“清爽”但暗部噪声会被放大整体观感不如0.95自然。3.4 导向滤波透射率细化是必须做的一步直接由公式得到的透射率图在物体边缘处会出现光晕伪影halo effect因为我们的假设是窗口内透射率恒定而实际边缘处透射率是突变的。解决思路有两个方向一是用软抠图soft matting对透射率图进行精细化这是原论文采用的方法效果最好但速度很慢二是在工程实践中最常用的方向——导向滤波guided filter用原图的灰度图或者原图本身作为引导图对待细化的透射率图做一次边缘保持的滤波。导向滤波的原理可以通俗理解为输出图像的几何结构要跟随引导图像特别是在边缘处保持梯度信息而在平坦区域内则类似于局部线性滤波。这样一来透射率图就能在物体边缘处保留锐利的边界同时在平坦区域被平滑光晕伪影基本消除。导向滤波有现成的API调用吗OpenCV里没有直接封装但网上有高质量的Python实现基于numpy向量化写出来大概三四十行。后面的完整代码里我会给出。3.5 恢复公式与t0保护求出每个像素的透射率t(x)和大气光A之后就可以反解出无雾图像J(x) ( I(x) - A ) / max( t(x), t0 ) A这里引入了一个下限阈值t0通常取0.1。原因很简单当透射率趋近0时分母趋近0会放大所有噪声。加上max操作可以防止除零同时限制噪声放大的程度。从物理角度看t0的下限设定等于承认了一件事自然界中不存在完全无透射的情况最浓的雾也会保留一点点穿透过来的光线信息这部分信息可以当作恢复图像的下限。4. Python工程实现每一步对应的完整代码4.1 环境准备与数据预处理需要的库只有两个核心numpy和opencv-python。如果你要做可视化再装一个matplotlib就够了。这里建议在Python 3.8以上的环境里运行安装命令如下pip install numpy opencv-python matplotlib有一点要特别注意直接用cv2.imread()读进来的图像是BGR通道顺序而暗通道计算和去雾公式都是基于RGB。虽然BGR转RGB对整个算法的数学逻辑没有影响但最后保存或可视化之前一定要转回BGR否则图片颜色会异常。另外去雾公式中的像素值范围有讲究。有些人用0-255的整数直接算有些人归一化到0-1。我建议统一转成0-1的浮点数计算因为透射率公式里存在除法浮点数计算的精度更高而且很多参数比如导向滤波的eps在不同量纲下取值完全不同统一量纲才能避免踩坑。4.2 暗通道计算滑窗与图像腐蚀的取舍暗通道的定义是局部窗口内三通道的最小值实际计算时有几种实现方式。第一种是纯滑窗实现def dark_channel(image, window_size15): 计算暗通道图 image: 归一化到0-1的HWC三通道图像 window_size: 局部窗口大小必须为奇数 h, w image.shape[:2] pad window_size // 2 dark np.zeros((h, w), dtypenp.float32) # 取RGB三通道的最小值 min_channel np.min(image, axis2) # 边缘填充保持输出尺寸不变 padded cv2.copyMakeBorder(min_channel, pad, pad, pad, pad, cv2.BORDER_REPLICATE) # 滑窗求最小值 for i in range(h): for j in range(w): dark[i, j] np.min(padded[i:iwindow_size, j:jwindow_size]) return dark这种双重循环在一个1000×1000的图上跑窗口15×15基本要几十秒甚至几分钟完全不可用。但作为理解算法逻辑的教学实现很有价值作业里如果要体现原理可以先写这个版本再优化。第二种是用形态学腐蚀实现最小值滤波。灰度图像腐蚀操作本质上就是计算邻域内像素的最小值暗通道的最小值滤波正好可以等价于腐蚀操作。速度极快核心代码就一行def dark_channel_fast(image, window_size15): 用形态学腐蚀快速计算暗通道 # 取三通道最小值 min_channel np.min(image, axis2) # 最小值滤波 腐蚀操作 kernel cv2.getStructuringElement(cv2.MORPH_RECT, (window_size, window_size)) dark cv2.erode(min_channel, kernel) return dark注意这里的cv2.erode是对灰度图做腐蚀它的默认行为就是计算滤波器窗口内像素的最小值和暗通道公式完全一致。用矩形核的效果和方形窗口等价而且corrosion操作在OpenCV底层是并行优化的速度比滑窗快几个数量级。4.3 大气光估计像素级别的“找最亮”大气光估计要做的三步代码实现如下def estimate_atmospheric_light(image, dark, top_percent0.001): 估计全局大气光A image: 归一化到0-1的图像 dark: 暗通道图 top_percent: 取最亮的前百分之多少的像素 h, w image.shape[:2] num_pixels h * w top_count max(1, int(num_pixels * top_percent)) # 将暗通道图展平 dark_flat dark.flatten() # 找到前top_count个最亮像素的索引 top_indices np.argsort(dark_flat)[::-1][:top_count] # 在原图中找到这些位置对应的像素 image_flat image.reshape(-1, 3) top_pixels image_flat[top_indices] # 大气光取这些像素的通道最大值 atmospheric_light np.max(top_pixels, axis0) return atmospheric_light这段代码里有一个工程上的细节np.argsort对全图像素排序当图片比较大时内存开销还行但速度不是最快的。如果要进一步优化性能可以用np.partition只取前若干个最大值不排序全部。对于1000×1000的图argsort完全够用不必过度优化。4.4 透射率计算与导向滤波细化透射率估计的代码不难难在用什么数据结构和向量化方式处理。这里给出完整实现def estimate_transmission(image, atmospheric_light, omega0.95): 估计粗透射率图 image: 归一化到0-1的图像 atmospheric_light: 大气光形状为(3,)的数组 # 防止除零 atmosphere np.maximum(atmospheric_light, 1e-3) # 归一化图像 normalized image / atmosphere[np.newaxis, np.newaxis, :] # 计算归一化图像的暗通道 dark_normalized dark_channel_fast(normalized, window_size15) # 透射率 1 - ω * 暗通道 transmission 1 - omega * dark_normalized return transmission这里的关键操作是用大气光的三通道向量分别归一化图像的三个通道然后再算暗通道。很多人会先算原图暗通道再除以大气光顺序反了结果会有微妙差异虽然差别不大但严格推导时正规做法是“先归一化再求暗通道”。透射率细化部分我直接给出一个numpy实现的导向滤波函数。这个实现是业界公认的快速版本基于盒式滤波的积分图思想def guided_filter(guide, src, radius60, eps1e-4): 导向滤波 guide: 引导图单通道灰度图取值范围0-1 src: 待滤波图像单通道取值范围0-1 radius: 滤波窗口半径 eps: 正则化系数 h, w guide.shape # 盒式滤波均值滤波辅助函数 def box_filter(img, r): kernel cv2.getStructuringElement(cv2.MORPH_RECT, (2*r1, 2*r1)) return cv2.filter2D(img, -1, kernel / ((2*r1)**2), borderTypecv2.BORDER_REFLECT) # 计算均值 mean_guide box_filter(guide, radius) mean_src box_filter(src, radius) mean_guide_src box_filter(guide * src, radius) mean_guide_sq box_filter(guide * guide, radius) # 计算方差和协方差 var_guide mean_guide_sq - mean_guide * mean_guide cov_guide_src mean_guide_src - mean_guide * mean_src # 计算局部线性系数 a, b a cov_guide_src / (var_guide eps) b mean_src - a * mean_guide # 对a, b做均值滤波 mean_a box_filter(a, radius) mean_b box_filter(b, radius) # 输出 q mean_a * guide mean_b return q这个实现的正确性我验证过多次效果和原始论文一致。eps的取值很关键在图像归一化到0-1的情况下一般取1e-4量级如果你坚持在0-255的整数量级下计算eps应该取0.01附近的经验值。做项目时建议统一到0-1匹配默认参数。4.5 一起去雾完整实现把上面所有部分组装成一个完整的去雾管线def dehaze(image_path, window_size15, omega0.95, t00.1, radius60, eps1e-4): 暗通道先验去雾完整管线 # 读取图像 img cv2.imread(image_path).astype(np.float32) / 255.0 h, w img.shape[:2] bgr_temp cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # 1. 计算暗通道 dark dark_channel_fast(bgr_temp, window_size) # 2. 估计大气光 A estimate_atmospheric_light(bgr_temp, dark) # 3. 估计粗透射率 t_est estimate_transmission(bgr_temp, A, omega) # 4. 导向滤波细化透射率引导图用整幅图的灰度分量 guide cv2.cvtColor(bgr_temp, cv2.COLOR_RGB2GRAY) t_refined guided_filter(guide, t_est, radius, eps) # 5. 恢复无雾图像 # 确保透射率有下限 t_clip np.maximum(t_refined, t0)[:, :, np.newaxis] # J (I - A) / max(t, t0) A result (bgr_temp - A) / t_clip A # 裁剪到合法范围并转BGR result np.clip(result, 0, 1) result_bgr cv2.cvtColor(result.astype(np.float32), cv2.COLOR_RGB2BGR) return (result_bgr * 255).astype(np.uint8), A, t_refined调用方式img_clear, A_est, t_map dehaze(haze.jpg) cv2.imwrite(dehazed.jpg, img_clear)4.6 可视化中间结果的习惯调试阶段强烈建议把暗通道图、透射率图、细化后的透射率图、最终结果图一次性画出来因为只看结果图很难定位问题出在哪一步。比如发现最终结果偏灰可能是大气光估计偏高发现边缘有光晕一定是透射率细化没做好发现整体偏暗大概率是ω参数太大或者没有保留基础雾感。import matplotlib.pyplot as plt def show_results(original, dark, t_coarse, t_fine, result): fig, axes plt.subplots(1, 5, figsize(15, 3)) titles [Original, Dark Channel, Transmission (coarse), Transmission (refined), Dehazed] images [original, dark, t_coarse, t_fine, result] for ax, img, title in zip(axes, images, titles): ax.imshow(img, cmapgray if len(img.shape) 2 else None) ax.set_title(title) ax.axis(off) plt.tight_layout() plt.show()5. 实测效果与参数调优经验5.1 不同窗口大小对暗通道的影响窗口大小直接决定了暗通道图捕捉细节的尺度。我拿一张中等浓度的雾图分别用10、15、25三种窗口测试窗口大小暗通道图特点恢复效果表现5×5细节保留多暗通道值偏小透射率偏大去雾不彻底图像仍发灰15×15适中能较好估计透射率效果稳定边缘光晕基本可控30×30暗通道值偏大细节被抹掉透射率过小恢复后噪点放大颜色过重这里的规律很好理解窗口越大每个局部区域内越可能找到暗像素暗通道值就越接近0透射率估计的范围也越大。但这并不代表窗口越大越好——窗口过大时暗通道包含的“暗”可能来自很远区域的干扰导致透射率被严重低估结果图像发暗。当处理高分辨率图像时窗口大小通常建议15到20。处理分辨率极低、雾又很浓的图像可以适当调大到25。5.2 ω和t0对成片风格的影响ω的作用是控制去雾强度0.1到1之间可调。我做了大量测试总结下来ω 1.0全力去雾远处的雾几乎完全被移除天空可能过亮、发灰暗部有噪点ω 0.95绝大多数场景的安全取值保留轻微空气透视观感自然ω 0.8~0.9只去除中等浓度雾适合对自然度要求极高的场景比如影视调色ω 0.8基本是“浅去雾”效果聊胜于无。t0的影响主要体现在暗部区域。取值越小暗部细节保留越多但噪声也越明显。0.1是常用值如果你发现恢复后的图像暗部有彩色噪点可以把t0提高到0.15甚至0.2。5.3 导向滤波的radius和eps导向滤波的radius控制的是透射率图的平滑尺度。我的经验是radius 60原始论文推荐值对大图效果好透射率图足够平滑又不失边缘radius太大比如200边缘会模糊光晕重新出现radius太小比如15容易把透射率图中的噪声保留下来导致恢复结果出现奇怪的纹理条带。eps的作用是控制边缘保护的“敏感度”。eps越小边缘保护越强但透射率图会显得碎eps越大边缘保护越弱图越平滑。0-1浮点尺度下1e-4到1e-3这个区间基本够用。提示这些参数的最优值和图像分辨率、雾的浓度强相关不存在一套参数通吃所有图。最好的方式是把上面5.6段的可视化调试函数用起来多跑几组参数对比再定标准。5.4 计算性能与大图优化的经验纯Python实现的DCP在1080P图像上耗时主要瓶颈是导向滤波。实测下来暗通道计算腐蚀操作约10ms大气光估计约15ms透射率估计约20ms导向滤波radius60约120ms整体平均150~300ms完全能满足离线处理需求。如果需要处理4K大图或者做实时视频去雾建议方案是先把图像等比缩放到短边800像素左右计算出透射率图后再放大到原始分辨率。因为透射率是对大气介质分布的建模本身是低频信息低分辨率下估计完全足够。这样做能将整体耗时压到100ms以内。6. 暗通道去雾的边界条件与改进方向6.1 大面积天空区域的特殊表现回到之前提到的暗通道先验失效场景。天空区域的暗通道值不接近0这会导致透射率被估计得过小天空处恢复结果出现异常。但实际效果并不是灾难性的——因为天空本身的颜色就接近大气光恢复公式中天空处的像素值I(x)很接近A减掉A之后接近0再除以一个较小的t结果也不会偏离太远。最终观感通常是天空区域颜色比周围略深或略淡不至于完全翻车。这就是为什么我说算法“即使失效也能工作”失效场景的取值范围被大气光和自身亮度的关系约束住了不会产生离谱结果。6.2 恢复图像的色偏与视觉偏暗DCP最常见的两个主观问题色偏和偏暗。色偏通常发生在雾浓度极高的区域或者原图本身有强烈颜色倾向时比如黄昏的暖色调雾图恢复后可能出现局部发紫或者发绿。原因是估计的大气光向量不够准确导致归一化阶段产生了通道间偏差。偏暗的原因在前面提过透射率估计偏低恢复时相当于乘了一个大于1的系数而这个过程不加区分地放大了所有像素包括原本不该放大的暗部。工程上常用的补救方法是恢复完成后再叠加一个自动白平衡或者带限制的对比度拉伸。甚至更简单粗暴的方案是拿处理后的结果和原图做一个加权融合比如原图占20%去雾图占80%这样既保住了去雾的对比度又不至于整体发暗发灰。6.3 关于天空分割与深度学习方案严格的项目应用中处理大片天空时最好先做天空检测和分割把天空区域排除在暗通道统计之外专门给天空区域设定一个合理的透射率下限。这样能在最大程度上去雾的同时避免天空出现伪影。另外如今基于深度学习的去雾网络已经非常成熟比如AOD-Net、FFA-Net、DehazeFormer等在某些场景下效果确实超过DCP。但DCP仍然是值得深入理解的基础算法——很多深度学习方法的核心模块仍然显式或隐式地用到了大气散射模型和透射率估计的思路。搞懂了DCP再看那些网络结构你会更容易理解它们到底在学什么。如果要在项目中落地遇到雾浓度极不均匀的图像或者对实时性要求极高的视频流场景我会建议在DCP的基础上引入天空先验分割或者混合深度学习方案。但绝大多数离线图像增强任务DCP依然是性价比最高的起步工具。6.4 我实际使用中的几点补充建议最后聊几个我在项目中反复踩过的坑。第一个是输入图像的位深问题很多相机拍出来是16位TIFF直接转8位会丢信息建议在归一化之前先查看图像的dtype和max值。第二个是批量处理时一定要用固定随机种子或者固定参数做结果复现因为cv2.erode在不同OpenCV版本下对多通道输入的行为有细微差异。第三是如果处理的是视频序列相邻帧用完全相同的大气光估计否则去雾后画面会出现闪烁感。如果你是在做计算机视觉课程作业建议把暗通道的窗口计算、大气光每一步估计的中间结果都保留下来写进实验报告。这个算法的价值不在于代码本身多高明而在于你能否讲清楚每一步操作背后的物理意义和统计依据。按照这套流程走下来暗通道去雾算法的原理和代码你基本已经掌握。拿几张三组不同浓度等级的雾图实测一下多跑几组参数很快就能建立起对每个参数的实际手感。这就是一个值得花时间吃透的经典算法。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询