尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

图像分割与图像增强源码包详解:从直方图均衡到马尔可夫随机场

发布时间:2026/9/23 20:53:10

资讯中心
01
ARTICLE

图像分割与图像增强源码包详解:从直方图均衡到马尔可夫随机场

图像分割与图像增强源码包详解:从直方图均衡到马尔可夫随机场
简介一个面向计算机视觉初学者的Python源码复现包聚焦图像分割与图像增强两大经典方向适合正在学习OpenCV与基础算法的读者对照实践。内容包含最大类间方差法OTSU、迭代阈值分割、最大熵阈值分割、马尔可夫随机场分割等分割实现以及单尺度SSR、多尺度MSR、直方图均衡、自适应直方图均衡AHE/CLAHE等增强方法每种算法均配有自写代码与参考程序便于对比理解。压缩包共28个文件以17个py源码为主辅以测试图片、Markdown说明、运行帮助文本及一份PDF格式的实验报告整体大小仅2.46MB轻量但覆盖全面。已有584人学习下载适合作为入门图像处理算法时的动手参考资料可直接运行查看效果并逐步注释学习。1. 计算机视觉入门这份图像分割与图像增强源码包适合拿来直接复现多数人学计算机视觉第一步就扎进深度学习但课程作业、毕设起步、竞赛预处理真正能兜底的还是经典图像处理算法。这份源码包正好踩在这个点上图像增强一侧有直方图均衡、CLAHE、单尺度SSR、多尺度MSR、亮度均值直方图均衡图像分割一侧有OTSU、最大熵阈值、迭代阈值、Canny边缘检测外加一个马尔可夫随机场分割。全部是Python源码带中文注释配套lena.png和fog_road.jpg两张测试图适合需要快速跑通算法、看懂每一步在干什么的入门者和做课程设计的学生。和网上零散抄来的demo不一样这套资源里每类算法都给了参考程序和自写代码两个版本对照着看能很直观地明白同一思路的不同实现差异。下面按增强、分割、统计模型、排错、验证的顺序把它拆开讲。2. 图像增强直方图均衡与Retinex参数怎么设才不翻车图像增强部分占了源码包将近一半的篇幅覆盖了从像素级操作到物理模型的两种主流思路。直方图均衡系处理的是灰度分布Retinex系处理的是光照估计两类方法各有各的适用场景和调参套路。2.1 直方图均衡与CLAHE对比度拉开的代价是噪声直方图均衡的核心逻辑是把灰度直方图从集中分布映射到接近均匀分布。代码里直方图均衡zixie.py实现得比较朴素先统计灰度级频率再算累计分布函数最后用CDF做灰度映射。import cv2 import numpy as np import matplotlib.pyplot as plt def hist_equalize(image): # 统计256个灰度级 h, w image.shape hist np.zeros(256, dtypenp.int32) for i in range(h): for j in range(w): hist[image[i, j]] 1 # 计算累计分布函数CDF cdf np.zeros(256, dtypenp.float64) cdf[0] hist[0] / (h * w) for k in range(1, 256): cdf[k] cdf[k-1] hist[k] / (h * w) # 用CDF做灰度映射 lut np.round(cdf * 255).astype(np.uint8) return cv2.LUT(image, lut)纯Python逐像素遍历统计直方图这部分在工程上效率不高但优点是逻辑外露适合对照公式理解。cv2.LUT查表是最终执行映射的高效方式免去了逐像素赋值的等待。默认映射档位是256级如果输入是12bit或16bit图像需要先归一化到8bit。直方图均衡的毛病是过增强原本集中的灰度区被拉开后平滑区域的噪声跟着被放大天空、墙面这类区域容易出现色块断层。源码里给的CLAHE.py就是针对这个问题做的自适应版本cv2.createCLAHE的clipLimit和tileGridSize是两核心参数。import cv2 img cv2.imread(fog_road.jpg) gray cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) clahe cv2.createCLAHE(clipLimit2.0, tileGridSize(8, 8)) enhanced clahe.apply(gray) cv2.imwrite(CLAHE_result.jpg, enhanced)clipLimit控制在局部直方图裁剪后重新分配的比例实践经验是2.0到3.0之间比较中庸tileGridSize把图像切成8x8的块在每个小块内分别做均衡。CLAHE_cv2.py是同一算法的OpenCV原生版本比手写版快不少。实际用起来雾图、低照度图、X光片这类对比度不均的图优先试CLAHE清爽的普通图直接直方图均衡即可。亮度均值直方图均衡zixie.py是在原图基础上先做了亮度归一化再均衡适合整体偏暗的输入但注意它对本身动态范围很大的图容易丢失亮部细节。2.2 Retinex系列SSR和MSR的尺度参数才是灵魂Retinex模型的核心假设是一幅图像可以由入射分量和反射分量相乘得到入射分量是光照变化平缓反射分量是物体本色信息量集中。算法要做的就是从原图中分离出反射分量从而消除光照不均的影响。单尺度SSR.py用高斯滤波估计光照在log域里做减法再还原回线性域。import cv2 import numpy as np def SSR(img, sigma80): # 转float并归一化到[0,1] img img.astype(np.float32) / 255.0 # 高斯模糊估计入射分量 gaussian cv2.GaussianBlur(img, (0, 0), sigma) # log域相减得到反射分量 log_R np.log(img 1e-6) - np.log(gaussian 1e-6) # log域还原回线性域 result np.exp(log_R) # 归一化到0-255 result cv2.normalize(result, None, 0, 255, cv2.NORM_MINMAX) return result.astype(np.uint8) img cv2.imread(fog_road.jpg) result SSR(img, sigma80) cv2.imwrite(SSR_result.jpg, result)高斯核的sigma在这里配合(0,0)使用OpenCV会依据sigma自动计算核大小。sigma偏小比如10以下时高斯核覆盖区域窄光照估计会带进过多纹理细节结果容易出现光晕伪影sigma偏大200以上时估计过于平滑增强效果趋近于全局操作局部阴影去不掉。我一般习惯在标准测试图上先跑sigma80再根据输出噪点情况上下调。多尺度MSR.py把SSR在不同sigma下的结果加权合并弥补单尺度在亮区和暗区不能兼顾的问题。常见设置是三个尺度sigma取15、80、250权重各占三分之一源码里也是这么写的。多尺度的代价是三个尺度的log域结果合并后反射分量的动态范围会被压缩整体发灰所以代码里通常会在最后加一个增益补偿或直方图拉伸。文件里的MSR.jpg如果看着偏灰不一定是你跑错了很可能就是没做最后的动态范围调整。2.3 fog_road.jpg的实际表现与参数参考以源码包自带的fog_road.jpg为例这是一张带雾气的道路场景光照分布不均近处地面和远处天空亮度差距大。不同增强算法在它上面的表现差异非常明显这也是原作者选它当测试图的原因。下面是我在复现时验证过的一组参数。算法核心参数视觉效果适用备注直方图均衡无整体对比度提升天空噪点变明显雾图可用但细节恢复有限CLAHEclipLimit2.5, tile8x8近处纹理清楚远处细节尚可最稳的兜底方案SSRsigma80去雾明显暗部偏灰单尺度速度快适合视频帧处理MSRsigma15/80/250动态范围保留最好需要后处理静态图推荐算力消耗大三倍亮度均值均衡无亮度归一化后细节提升对偏暗图友好对过曝图效果一般有一点值得特别说fog_road.jpg的雾气是全局性的Retinex算法对它效果明显如果换成人脸背光图SSR可能在阴影边缘处产生光晕那种情况反而更适合先提亮度再局部均衡。选增强算法时先看缺陷来源光照不均选Retinex对比度不足选直方图系两者叠加就组合使用这是不分框架的通用判断路径。3. 图像分割阈值分割三件套与Canny边缘检测的实现细节图像分割部分几乎覆盖了课堂教学的全部经典阈值法。OTSU、最大熵、迭代阈值三者的目标函数不同适用的直方图形状也不同。Canny作为边缘检测的标杆算法参数调起来有很多讲究。3.1 OTSU最大类间方差阈值自动找但直方图形状决定成败OTSU的核心思想是按当前阈值把像素分成前景和背景两类遍历所有灰度级找到使两类间方差最大的那个阈值。类间方差本质上是两类均值的加权离散度前景和背景区分越开方差越大。源码里最大类间方差法zixie.py的写法值得看一段。import numpy as np import cv2 def otsu_threshold(gray): hist cv2.calcHist([gray], [0], None, [256], [0, 256]).ravel() total gray.size sum_all np.dot(np.arange(256), hist) sum_bg 0 weight_bg 0 max_var 0 best_thresh 0 for t in range(256): weight_bg hist[t] if weight_bg 0: continue weight_fg total - weight_bg if weight_fg 0: break sum_bg t * hist[t] mean_bg sum_bg / weight_bg mean_fg (sum_all - sum_bg) / weight_fg # 类间方差公式 var_between weight_bg * weight_fg * (mean_bg - mean_fg) ** 2 if var_between max_var: max_var var_between best_thresh t return best_thresh img cv2.imread(lena.png, cv2.IMREAD_GRAYSCALE) thresh otsu_threshold(img) _, binary cv2.threshold(img, thresh, 255, cv2.THRESH_BINARY)遍历从0到255完整扫一遍复杂度O(256)对单通道图来说开销可以忽略。weight_bg和weight_fg分别是两类像素占比mean_bg和mean_fg是两类灰度均值var_between越大说明分割越彻底。cv2.threshold里也可以直接用cv2.THRESH_OTSU标志但自己写一遍能清楚看到每一步在算什么。OTSU的前提假设是直方图近似双峰分布。lena.png这种亮度分布均匀的图OTSU跑出来的阈值很稳定但如果目标是严重偏亮或偏暗的单峰图OTSU会把峰边缘切进去分割结果就是大片的黑白块。遇到这种图先查直方图形态单峰就别硬上OTSU。3.2 最大熵与迭代阈值熵最大和均值逼近的差别在哪里最大熵阈值分割的出发点是信息论。分割后的前景和背景各自的熵总和达到最大时两类内部的灰度分布最均匀也就是说边界切的位置最不武断。基于最大熵-阈值分割.py的实现一般是在每个候选阈值处分别统计前景和背景的灰度概率分布再计算各自的熵并求和。import numpy as np import cv2 from math import log def max_entropy_threshold(gray): hist cv2.calcHist([gray], [0], None, [256], [0, 256]).ravel() total gray.size prob hist / total max_ent 0 best_thresh 0 for t in range(256): # 前景与背景概率分别归一化 p_bg prob[:t1] p_fg prob[t1:] sum_bg p_bg.sum() sum_fg p_fg.sum() if sum_bg 0 or sum_fg 0: continue # 归一化后计算各自己的熵 ent_bg -np.sum(p_bg / sum_bg * np.log(p_bg / sum_bg 1e-10)) ent_fg -np.sum(p_fg / sum_fg * np.log(p_fg / sum_fg 1e-10)) ent_total ent_bg ent_fg if ent_total max_ent: max_ent ent_total best_thresh t return best_thresh最大熵对直方图形状不敏感不需要双峰假设抗噪性比OTSU略好。代价是log运算在Python循环里略慢256个灰度级扫下来能明显感到比OTSU迟滞实际批量处理时可用numpy向量化改写。log里加1e-10是防概率为0时出现负无穷这个细节在下阈值处尤其关键。迭代阈值分割走的完全是另一条路。它先给一个初始阈值通常是灰度均值然后按当前阈值把像素分成两类、分别求灰度均值再把两个均值的均值作为新阈值循环直到阈值变化量小于设定精度。迭代阈值分割zixie.py的实现里有个容易踩坑的点初始阈值如果偏离实际分割点太远迭代次数会显著增多部分实现会设置最大迭代次数兜底。import cv2 import numpy as np def iterative_threshold(gray, max_iter100, eps0.5): # 初始阈值取整幅图灰度均值 t_cur gray.mean() for i in range(max_iter): bg gray[gray t_cur] fg gray[gray t_cur] if len(bg) 0 or len(fg) 0: break t_new (bg.mean() fg.mean()) / 2 if abs(t_new - t_cur) eps: break t_cur t_new return round(t_cur) img cv2.imread(lena.png, cv2.IMREAD_GRAYSCALE) thresh iterative_threshold(img) _, binary cv2.threshold(img, thresh, 255, cv2.THRESH_BINARY)eps是收敛精度0.5意味着阈值波动在半级灰度内就停。max_iter100在绝大多数图上十几轮就会收敛。迭代阈值本质是不断逼近两类灰度均值的中间点对初始值敏感度一般但它假设两类像素数量差距不是特别悬殊如果目标区域只占全图的5%最终阈值会偏向背景。3.3 Canny边缘检测双阈值远比想象中重要Canny_zixie.py把Canny的完整流程拆成了四段高斯滤波去噪、Sobel算梯度幅值和方向、非极大值抑制、双阈值滞后连接。OpenCV一行cv2.Canny()能完成的事自写版本里每一步都有独立的中间结果输出这对理解边缘检测的原理非常有帮助。import cv2 import numpy as np def canny_edge(gray, low_thresh, high_thresh): # 1. 高斯降噪 blurred cv2.GaussianBlur(gray, (5, 5), 1.0) # 2. Sobel求梯度 gx cv2.Sobel(blurred, cv2.CV_64F, 1, 0, ksize3) gy cv2.Sobel(blurred, cv2.CV_64F, 0, 1, ksize3) magnitude np.sqrt(gx**2 gy**2) angle np.arctan2(gy, gx) * 180 / np.pi # 3. OpenCV内置Canny完成非极大值抑制和双阈值 edges cv2.Canny(blurred, low_thresh, high_thresh) return edges img cv2.imread(lena.png, cv2.IMREAD_GRAYSCALE) edges canny_edge(img, low_thresh50, high_thresh150)Canny的默认参数组合在OpenCV里是threshold1100, threshold2200这个组合对大多数自然图像偏保守。经验法则是high_thresh设为low_thresh的2到3倍参考程序里给的比如是50和150就符合这个区间。low_thresh决定哪些梯度幅值能作为弱边缘被保留high_thresh决定哪些强边缘能直接确认。高阈值太小会导致大量毛刺边缘高阈值太大则会切断本该连续的轮廓。边缘_Canny.py这个文件里还有一组实验对比了不同sigma和阈值下的边缘密度跑之前建议先把lena.png转成灰度再进Canny。彩色图直接跑Canny会分别在三个通道上独立计算得到的边缘图是三个通道的叠加效果轮廓位置有时会出现重影。4. 马尔可夫随机场图像分割把像素关系纳入能量函数阈值法和边缘检测都是逐像素独立判断没有利用像素之间的空间关系。马尔可夫随机场分割把图像当作一个图结构给每个像素分配标签时同时考虑像素自身的观测特征和邻域的一致性。这是这套源码包里理论上限最高的一个算法也是初学者理解起来最吃力的一部分。4.1 能量函数是MRF分割的核心抓手马尔可夫_知乎.py和马尔可夫_遍历.py两个文件实现思路一致构造能量函数通过迭代最小化能量来逼近最优标签分配。数据项衡量当前像素灰度与标签分布的匹配程度平滑项惩罚相邻像素标签不一致的情况。import numpy as np from scipy import ndimage def mrf_segmentation(img, n_labels2, beta1.0, max_iter50): h, w img.shape labels np.random.randint(0, n_labels, size(h, w)) # 每个标签对应一个高斯分布先做初始估计 mu [img[labels k].mean() for k in range(n_labels)] sigma [img[labels k].std() 1e-6 for k in range(n_labels)] for it in range(max_iter): for i in range(h): for j in range(w): # 当前像素灰度 pixel img[i, j] min_energy float(inf) best_k labels[i, j] for k in range(n_labels): # 数据项灰度偏离标签均值越大能量越高 data_cost (pixel - mu[k]) ** 2 / (2 * sigma[k] ** 2) # 平滑项统计邻域中不同标签的数量 smooth_cost 0 for di in [-1, 0, 1]: for dj in [-1, 0, 1]: ni, nj i di, j dj if 0 ni h and 0 nj w: if labels[ni, nj] ! k: smooth_cost beta total_energy data_cost smooth_cost if total_energy min_energy: min_energy total_energy best_k k labels[i, j] best_k # 更新标签均值 for k in range(n_labels): if np.sum(labels k) 0: mu[k] img[labels k].mean() sigma[k] img[labels k].std() 1e-6 return labelsbeta是平滑项权重它决定邻域一致性对分割结果的影响程度。beta过小分割结果会保留大量噪声孤点beta过大细小结构会被直接抹平。我在lena.png上试过beta从1.0调到2.5时帽子边缘的羽化细节被吞掉了一部分beta低于0.5时帽檐附近出现大量椒盐式误分。sigma分母里的1e-6是防高斯方差为0时除零报错。4.2 遍历实现与收敛边界别在迭代里迷失马尔可夫_遍历.py用的是逐像素遍历更新加重复迭代的策略。这个方案写起来直观但问题也明显256x256的图两标签50次迭代意味着要跑650万次像素级能量计算纯Python环境下耗时是分钟级别。自写代码里没有做任何向量化优化学习是够用的工程上用就会暴露性能问题。文件实现方式迭代次数边界情况马尔可夫_知乎.py参考程序带详细注释默认10-20轮标签可能收敛到局部最优马尔可夫_遍历.py自写逐像素遍历默认50轮迭代过多导致过平滑参考程序原版实现依赖初始标签随机初始化会导致结果不稳定初始标签的影响容易被忽略。随机初始化时不同随机种子的最终分割结果可能不同这是MRF能量函数非凸导致的多局部最优问题。实操时我用固定种子来做可复现实验或者先用OTSU的结果做初始标签明显比随机初始化稳定得多。4.3 邻域形式和标签数选择直接影响分割效果马尔可夫_知乎.py里用的是4邻域马尔可夫_遍历.py里用的是8邻域。4邻域平滑约束更弱8邻域对斜向边缘的连续性约束更强。在lena.png这种圆弧轮廓较多的图上8邻域通常表现优于4邻域因为对角线方向的标签变化也能被惩罚到。标签数n_labels默认等于类别数分割lena.png这种灰度分布清晰的图设2就够如果目标是从背景里抠出多个物体设3到5都可以。但标签数一旦超过实际类别MRF会把同一物体切碎分配给多个标签而且平滑项会让碎块之间出现明显的边界缝合痕迹。5. 图像分割与增强源码复现的常见问题排查从shape报错到噪声爆炸这套源码包我在复现时踩了不少坑有一些问题几乎每个跑这套代码的人都会遇到。按现象、原因、解决的顺序整理了五条覆盖从代码崩溃到结果不符合预期的典型场景。5.1 彩色图当灰度图读shape对不上引发cv2.error现象cv2.cvtColor或者cv2.threshold直接报错错误信息多是通道数不匹配或者某个函数内部断言失败。原因原图是BGR三通道但代码逻辑默认输入是单通道灰度图。直方图均衡zixie.py里的h, w image.shape如果传进来的是彩色图shape解包会直接失败。解决统一在入口处用cv2.imread(path, cv2.IMREAD_GRAYSCALE)读图或者在预处理第一行加灰度转换。如果是要跑SSR/MSR这类需要三通道独立处理的算法保留BGR格式、分别在三个通道上做Retinex再合并比整体转灰度信息损失小。5.2 Retinex增强后图像整体发灰或过曝现象SSR跑完输出像蒙了一层灰纱MSR跑完暗部细节是有了但整张图灰蒙蒙要么就是亮部爆成一片白。原因log域运算后的反射分量动态范围非常大直接取指数还原会超出0-255显示范围。SSR的sigma选太小时边缘附近会产生光晕表现就是过曝带MSR多尺度叠加后整体偏灰是反射分量压缩的自然结果。解决做一次线性归一化还不够我一般会在归一化后用cv2.createCLAHE做一次局部对比度恢复或者用gamma校正把中间灰度拉回来。另一个有效做法是只取反射分量的彩色信息、把光照分量替换成目标亮度也就是常说的亮度重建效果比直接拉伸好一档。5.3 OTSU和最大熵分割结果全是黑或全是白现象阈值跑出来是0或者255二值化后整幅图像几乎全黑或全白。原因直方图是单峰分布时OTSU找出的类间方差最大值出现在直方图边缘阈值被推到灰度范围的端点。最大熵分割也类似当一类像素占比极小熵的贡献被另一类主导。解决先用cv2.calcHist看直方图形态确认是否有两个明显峰。如果单峰考虑用自适应阈值cv2.adaptiveThreshold或者接受分割结果后做形态学开闭运算滤掉小块误分区域。迭代阈值在这个场景下通常表现得比OTSU好因为它天然受到两类均值约束不容易把阈值推到极端值。5.4 Canny边缘断裂或细碎毛刺一大堆现象边缘检测结果里需要连续闭合的目标轮廓断成了好几截同时背景里的纹理噪声全部被当作边缘保留。原因湍流是双阈值设置不够合理。low_thresh太低导致弱边缘过多high_thresh太高导致部分真实边缘因为梯度幅值不够被剔除。断裂主要发生在边缘亮度梯度不一致的区域——边缘线上一段梯度高一段梯度低低梯度段被阈值卡掉了。解决先固定high_thresh为low_thresh的2.5倍再整体上下调整。尽量不要只动一个阈值比例失衡会让边缘密度突变。针对断裂问题可以在cv2.Canny之后接形态学闭运算核大小3x3把断口连接起来针对毛刺问题开运算去噪。还有一个偏门但好用的技巧先对灰度图做CLAHE增强再进Canny弱边缘的梯度会被拉起来边缘连续性明显改善。5.5 MRF分割速度慢到怀疑人生现象256x256的图跑50轮迭代Python环境里等了好几分钟才有结果调整参数时每轮都要等调试效率极低。原因逐像素遍历加逐标签能量计算双重循环的复杂度是O(iterations x pixels x labels x neighbor_size)即使200x200的小图也是几千万次操作纯Python解释器执行瓶颈明显。解决调试阶段把迭代次数降到5到10轮确认逻辑没问题再拉满把图像resize到128x128跑通全流程。除此之外可以把能量计算里与标签无关的项提前算好缓存邻域平滑项用卷积替代显式循环。最终工程化时建议改用ICM迭代条件模式而不是全局遍历更新ICM每个像素只与当前状态比较收敛速度能快一个量级。6. 源码复现后的效果验证三张图判断每个算法有没有跑对跑通了不代表跑对了算法实现错误时输出结果有时看起来也像那么回事。我给自己定了一套固定的验证流程不管换什么测试图都按这个顺序过一遍基本能拦住90%的实现偏差。第一张图是灰度直方图。直方图均衡、CLAHE这类增强算法的效果必须能在直方图上看到变化均衡后的直方图灰度分布应该铺得更开CLAHE的直方图则呈现多峰的局部拉伸形态。Retinex的输出直方图通常表现为整体向右偏移因为反射分量被归一化后整体亮度提高了。import cv2 import matplotlib.pyplot as plt img cv2.imread(CLAHE_result.jpg, cv2.IMREAD_GRAYSCALE) hist cv2.calcHist([img], [0], None, [256], [0, 256]) plt.figure(figsize(8, 4)) plt.plot(hist, colorblack) plt.title(Grayscale Histogram after CLAHE) plt.xlabel(Intensity) plt.ylabel(Pixel Count) plt.xlim([0, 255]) plt.show()第二张图是分割结果与原图的叠加可视化。二值掩膜以半透明方式叠加在灰度图上可以直观看到分割区域是否贴合目标轮廓。特别是MRF分割叠加图能看出碎块分布是否均匀、边界处是否有锯齿或者跨边界误分。import cv2 import numpy as np img cv2.imread(lena.png) gray cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) _, binary cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY) overlay img.copy() overlay[binary 0] (0, 0, 255) # 分割区域标红 cv2.imwrite(segmentation_overlay.jpg, overlay)第三张图是中间过程的可视化图。Canny自写代码里高斯模糊后的中间结果、Sobel梯度幅值图、非极大值抑制后的细线图每张都保存下来对比就能定位到边缘断裂发生在哪一步。这个方法同样适用于MRF每一轮迭代后的标签图保存下来能看到收敛轨迹——如果前几轮标签剧烈变化、后几轮几乎不动说明收敛正常如果50轮还在跳变初始标签或beta一定有问题。从那以后我每次复现CV源码包都会强制走一遍这套三图验证流程直方图确认增强、叠加图确认分割、过程图确认中间步骤。这套源码包里自带的实验报告PDF和Readme.md信息量不小建议先读Readme再动代码能让这部分验证少走很多弯路。希望帮到你。本文还有配套的精品资源点击获取
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。