新闻详情

新闻详情

首页 / 资讯中心 / 详情

基于RankIQA的无参考图像质量评价与人脸识别应用

发布时间:2026/9/24 23:38:08来源:尧图网络
基于RankIQA的无参考图像质量评价与人脸识别应用
简介基于Python的无参考图像质量评价实现包含完整源码与配套数据面向图像处理与计算机视觉方向的学生和开发者。压缩包内共274个文件压缩后约12.37MB其中包含163个Python脚本、Caffe模型配置prototxt、预训练checkpoint以及Markdown说明文档等覆盖失真图像生成、网络训练、模型评估全流程。项目针对人脸图像场景将网络输入从224降至128重新训练并提供了用小型网络拟合RankIQA的回归网络以及同时预测人脸角度和图像质量的联合训练脚本针对低质量图像性能差的问题代码中对质量标签做非线性拉伸至0-10便于复现和二次开发。目前已有1280人学习下载适合希望快速上手无参考图像质量评价或在此基础上扩展研究的进阶学习者。1. 无参考图像质量评价为什么我会把它放在人脸识别的第一步我接手过一个抓拍机的人脸检索项目上线后误报率高得吓人。排查到最后发现大量失败请求来自同一个环节输入框里塞进一张严重虚化或大角度侧脸的照片后续特征提取、比对全部白费。传统做法想用PSNR、SSIM判断图像能不能用但做无参考图像质量评价时根本没有原图可参照。这个基于Python的无参考图像质量评价项目解决的正是这个问题不给原图只给一张图像让网络预测质量分判断它适不适合送入后续识别链路。它基于RankIQA的排序思想用合成失真数据训练排名能力再针对人脸小目标把输入从224降到128重新训练还提供了同时预测人脸角度与质量分的多任务训练脚本。适合做安防、考勤、人像质量评估或者想直接跑通一套NR-IQA源码的开发者。2. RankIQA的训练流程用排序替代绝对分数失真数据与排序损失怎么搭2.1 为什么RankIQA用排序而不是直接回归无参考图像质量评价最难的不是网络结构而是标签。让人工给一张图打绝对质量分主观性非常强同一个标定员隔几天打分都会有明显波动给一群人打分同一个图可能分布在3到7分之间。但让标注员判断“这张比那张清楚”就稳定得多。RankIQA就是利用这个特性把质量评估从绝对分数回归改成相对排序整个训练流程分成Rank阶段和Regression阶段。Rank阶段用Siamese网络共享权重输入同一张图的两个失真版本网络分别输出质量分通过排序损失让高质量图的得分高于低质量图。这个阶段完全不需要绝对标签只需要知道两张图谁的失真更重样本生成成本极低。Regression阶段再把排序网络拿去做绝对分数微调让输出能回归到0到10这样的标度上。这个资源里的src和_src目录分别对应输入128和224的两次训练代码底层思想就是RankIQA的这套两阶段流程。Rank阶段里合成失真数据是关键约束。如果失真类型太单一网络只学会了分辨模糊无法泛化到噪声、压缩等真实退化。这个项目的data目录是distortion的matlab代码生成Rank网络需要的不同等级图像我一般会保留模糊、噪声、JPEG压缩三种失真每种再按强度划分4到5个等级保证排序对的数量足够。2.2 data目录下失真图像生成方式data目录里是matlab代码用同一张原图生成不同失真等级。以高斯模糊为例通过sigma列表控制等级sigma越大图像越模糊排序关系天然成立。% generate_rank_data.m % 对同一张图生成4个等级的高斯模糊用于构造排序对 img imread(face.png); sigma_list [0, 0.8, 1.6, 2.5]; % 模糊强度递增0表示原图 for i 1:length(sigma_list) if sigma_list(i) 0 deg_img img; else deg_img imgaussfilt(img, sigma_list(i)); end score 10 * exp(-sigma_list(i) / 2.5); % 简单映射后续可替换为人工label imwrite(deg_img, sprintf(rank_%d_%.2f.jpg, i, score), jpg, Quality, 95); end这段代码的核心是sigma_list。它决定了失真等级的跨度跨度太小两张图人眼都分不出差异排序网络会学到无意义的分类跨度太大比如直接从0跳到10网络会过度依赖某个明显的伪影特征反而忽略中间段的质量差异。我通常会让sigma覆盖0到3左右的区间并保证相邻等级在视觉效果上间隔均匀。score列里的指数映射只是临时用的真正训练时会在Regression阶段重新用人工标注的绝对分数Rank阶段只负责学相对关系。生成完不同等级图像后训练时随机抽同一源图的两张失真图作为一对根据sigma大小打标签。如果第一张的sigma小于第二张就标记为正样本对要求模型对第一张输出更高分。对rank loss来说这个二值标签足够了。2.3 排序损失与回归损失的差异Rank阶段和Regression阶段需要不同的损失函数。Rank阶段通常用margin ranking loss只约束相对大小Regression阶段换成Smooth L1或Huber loss让预测值贴近绝对标签。两者在实现上都比较简单。import torch import torch.nn.functional as F def ranking_loss(score_high, score_low, margin0.5): # 高质量图应该比低质量图高出至少margin loss torch.clamp(margin - (score_high - score_low), min0) return loss.mean() def regression_loss(pred, target): # 微调阶段使用SmoothL1对离群label更鲁棒 return F.smooth_l1_loss(pred, target)ranking_loss里的margin是关键参数。margin取0.1时网络只要分出高低就停止更新等级间的细微差异不被关注margin取1.0时网络会被迫让分数拉开足够距离但容易在噪声样本上过拟合。我在这个项目里先用0.5起步等SROCC稳定后再逐步减小。regression_loss里的SmoothL1比MSE更好因为质量分label本身有主观噪声MSE会对个别异常label产生很大的梯度SmoothL1在误差较大时梯度有上限训练更稳。到这里数据、网络和损失都齐全了理论上可以直接训练一个标准RankIQA。但这个项目真正花时间的地方在后面原始输入是224但人脸场景里大部分检测框实际只有几十到一百多像素直接抬到224会引入不少插值伪影。接下来就要看输入尺寸调整这件事。2.4 训练顺序与超参量级RankIQA的训练顺序不能乱。直接跳过Rank阶段用人工绝对分数训练很容易被label噪声带偏先Rank后Regression虽然多花时间但网络先学会了质量排序的底层特征微调阶段只需在低维空间做小幅度校正。我在这个项目里的顺序是先用Rank阶段训到SROCC不再上升再加载Rank模型权重换成回归头和SmoothL1用绝对质量分数训练。学习率方面Rank阶段用1e-3Regression阶段降到1e-4batch size选择32到64之间。如果你显存不大batch size降到8也行但要把margin适当调大一些因为小batch下排序对不够丰富。这里还有一个容易被忽略的点排序对的构造方式。如果每次随机采一对图像丰富度太低。常见做法是在一个batch内遍历所有等级组合让同一个源图的不同等级两两配对这样一次迭代就能产生C(n,2)个排序约束。具体实现时可以保存一个等级索引列表在dataloader里按索引组合抽取。另外无论Rank阶段还是Regression阶段数据集划分都不要乱打乱。排序对必须来自同一验证集不能把同一源图的某个等级放进训练、另一个等级放进验证否则SROCC虚高。我一般在生成mat数据时按源图路径切分保证一个源图的所有等级只出现在一个集合里。3. 网络结构裁剪输入从224降到128源码src与_src的区别和改法3.1 src与_src的差异224到128的改动点原版RankIQA代码基于ImageNet分类网络输入分辨率固定224×224也就是_src目录里那套代码。src目录则是为适应人脸大小把网络输入从224降到128重新训练的版本。这个改动不是简单把resize目标改小而是牵涉到网络结构、数据预处理和训练策略三层。为什么降到128人脸质量评估的实际输入不是整张大图而是人脸检测框裁出来的小块。在1080p抓拍画面中远处人脸检测框可能只有60到100像素强行resize到224会把原本就不多的细节放大三倍产生严重的插值纹理网络很容易把这些假纹理当作真实内容。降到128后resize倍数明显下降网络可以专注学习低分辨率下的真实退化模式。代价是某些需要高频细节的失真比如轻微散焦更难分辨这个后文避坑章会再展开。项目_srcsrc输入尺寸224×224128×128适用场景通用NR-IQA人脸检测后小框质量评估改动位置原始网络池化层替换、数据resize训练代价较高明显降低结构上224降到128后卷积特征图的尺寸从7×7变成4×4原版VGG后面的全连接层输入维度就对不上了。常见做法是把固定平均池化换成AdaptiveAvgPool2d((1,1))让任意输入尺寸都能跑到全连接层。import torch.nn as nn def get_backbone(input_size128): # 以VGG16为例去掉原固定7x7的avgpool改用GAP model torchvision.models.vgg16(pretrainedTrue) model.avgpool nn.AdaptiveAvgPool2d((1, 1)) # 原分类头最后输出1000类改成1维质量分 model.classifier nn.Sequential( nn.Linear(512, 128), nn.ReLU(inplaceTrue), nn.Dropout(0.2), nn.Linear(128, 1) ) return model这里的512来自VGG16最后一层卷积输出通道数换了backbone比如ResNet18会变成512或其他的值需要同步修改。AdaptiveAvgPool2d到(1,1)后不论输入是224还是128全连接层的输入维度都固定为512代码可以在两个输入尺寸之间直接切换这也是src和_src代码改动最小的迁移方式。要注意的是替换掉原来7×7的池化层之后模型能跑但backbone的BatchNorm统计量还是ImageNet的重新训练时前面几个epoch的loss可能比较奇怪这是正常现象。3.2 数据加载与预处理随输入尺寸一起改输入尺寸下降后数据加载端的resize、归一化、增强策略都要跟着调。比如resize目标从(224,224)改成(128,128)归一化均值和方差仍然沿用ImageNet的因为模型权重来自ImageNet预训练但增强的随机裁剪范围要收窄因为人脸区域本身比较紧凑。import cv2 import torch def load_face_image(path, size128): img cv2.imread(path) img cv2.cvtColor(img, cv2.COLOR_BGR2RGB) img cv2.resize(img, (size, size), interpolationcv2.INTER_AREA) img img.astype(float32) / 255.0 mean torch.tensor([0.485, 0.456, 0.406]).view(3, 1, 1) std torch.tensor([0.229, 0.224, 0.225]).view(3, 1, 1) x torch.from_numpy(img.transpose(2, 0, 1)) x (x - mean) / std return x这里的关键是interpolation参数。从大图直接缩小到128用INTER_AREA能平均像素区域保留整体结构如果用默认的INTER_LINEAR缩小时会丢失高频组件一些模糊差异反而不明显。平移、翻转这类增强也要注意随机水平翻转会影响人脸角度标签的yaw符号翻转后需要把角度label同步取反否则多任务训练时姿势head会被误导。3.3 regression_network用轻量网络拟合RankIQA效果完整RankIQA在推理时为了判断一张图的质量要么跑Siamese网络的一侧要么跑多次如果继续沿用Rank阶段的排序分支还有多分支融合的开销。这个项目里放了一个regression_network目录目的是用一个小网络拟合RankIQA的输出把推理成本压下来。常见做法是冻结Rank主干把最后一层卷积特征作为固定特征然后用一个三层MLP直接回归质量分。训练时以Rank模型的输出作为伪标签loss用SmoothL1。import torch.nn as nn class QualityRegressor(nn.Module): # 输入Rank网络提取的特征输出单图质量分 def __init__(self, feat_dim512, hidden128): super().__init__() self.net nn.Sequential( nn.Linear(feat_dim, hidden), nn.ReLU(inplaceTrue), nn.Dropout(0.2), nn.Linear(hidden, 1) ) def forward(self, feat): return self.net(feat).squeeze(-1)feat_dim要和主干特征维度对应。训练时如果直接用全连接特征特征里包含大量分类语义质量回归可能被类别信息带偏我更习惯取最后一层卷积的GAP特征只保留空间统计信息。这类小网络训练很快通常几十个epoch就收敛但它能继承多少Rank排序能力取决于伪标签的质量所以前一步Rank训练不能草率。4. 多任务训练用train_pose_qua.py同时预测人脸角度与质量分4.1 单任务先跑下限为多任务设置可对照的baselinetrain_pose_qua.py做的事情是让一个网络同时输出人脸角度和质量分数。这里的人脸角度通常指yaw、pitch、roll三个欧拉角来源可以是标注工具或人脸关键点拟合。多任务不是一上来就把两个loss别在一起因为在共享层同时学两个任务时梯度会相互影响你不知道当前差的到底是网络容量不够还是任务冲突。所以源码注释里强调先使用该网络分别完成单个任务观察最终loss可以下降到多少这个值就是这个网络性能的极限。具体做法是先屏蔽质量分支只训姿态再屏蔽姿态分支只训质量。记录两个任务各自的最小loss作为后续联合训练的下限。如果联合训练后两个loss都能回到这个水平说明共享特征图是够用的如果明显回不去就要调loss权重或者考虑增大共享层。我一般会用一组固定验证集来记录这个下限而不是只看训练loss。比如质量任务用验证集SROCC姿态任务用验证集MAE。因为训练loss可以压到很低但验证集一测就翻车尤其是在人脸角度这类回归任务上过拟合很容易。4.2 多任务Loss加权与分别打印的调参逻辑联合训练时两个loss相加后一起backward。直接相加的问题在于量级不一致如果姿态loss平均是0.3质量loss平均是0.7权重相等时质量任务会主导梯度。源码里给出的思路是加权后再求和并且在每个batch里分别打印两个任务的loss观察是否下降到单任务时的最小loss。alpha 0.6 # pose任务权重先根据单任务loss baseline设定 pose_loss criterion(pred_pose, pose_label) quality_loss criterion(pred_quality, quality_label) total_loss alpha * pose_loss (1 - alpha) * quality_loss total_loss.backward() print(fpose_loss{pose_loss.item():.4f} qa_loss{quality_loss.item():.4f})alpha的选取有个常规做法先用单任务baseline归一化alpha base_quality / (base_pose base_quality)。比如单任务时pose_loss是0.4quality_loss是1.2那么alpha取1.2/(0.41.2)0.75让两个任务在梯度量级上接近。这样处理完以后如果发现姿态任务仍然回不到下限说明共享特征更偏向质量学习可以把alpha往上加代价是质量任务的收敛会变慢。训练过程中如果看到某个batch里pose_loss突然跳高、quality_loss正常不要急着调alpha先看是不是ground truth标错尤其是人脸角度标注容易出现90度和-90度这种边界跳变。欧拉角回归对异常值非常敏感建议对label做sin/cos角度编码或者用SmoothL1抑制离群样本。4.3 共享backbone与两个head的结构设计多任务结构一般分成共享backbone和两个head。backbone用128输入的卷积网络姿态head输出3维质量head输出1维head只放一到两层全连接避免把任务特异的语义过早混进共享层。import torch.nn as nn class PoseQualityNet(nn.Module): def __init__(self, backbone): super().__init__() self.backbone backbone self.pose_head nn.Sequential( nn.Linear(512, 128), nn.ReLU(inplaceTrue), nn.Linear(128, 3) # yaw, pitch, roll ) self.quality_head nn.Sequential( nn.Linear(512, 128), nn.ReLU(inplaceTrue), nn.Linear(128, 1) # quality score ) def forward(self, x): feat self.backbone(x) pose self.pose_head(feat) quality self.quality_head(feat) return pose, quality共享backbone和两个head的拆法还有一个好处推理时可以根据业务场景只保留一个head。如果只做质量排序就把pose_head丢掉省一点计算量如果做人脸识别前筛选质量和角度两个分都要也可以直接取两个输出。这个设计比单独训练两个网络省内存而且角度信息能帮助质量head理解大角度侧脸造成的自遮挡。到这里训练脚本和网络结构基本摸清了。真正跑起来的时候问题往往不在这部分代码而在于数据分布和loss配合。下一章聊我踩过的几个坑。5. 避坑与常见问题低质量段不收敛、双任务loss冲突、训练NaN这几条坑不是理论推导是我在这个项目默认配置下实际撞过的墙。建议把训练脚本跑起来之前先读一遍能省不少反复试错的时间。5.1 低质量图像loss长期不降现象训练曲线到中段后高质量样本的预测准确率明显提升但低质量样本的loss基本横盘模型对模糊、噪声严重的图像打出的分数偏高。原因低质量图像在数据集中占比少且这些图像的label在1~3分区间分布不均匀来自不同失真类型的低分图在视觉上差异很大网络难以用一个连续函数覆盖。解决对质量label做非线性拉伸到0-10让低分段拉开差距。具体做法在后一章会写核心逻辑是用pow函数把低分区域的梯度放大让网络在低质量段获得更强的监督信号。5.2 双任务loss互相压制现象联合训练刚开始时两个loss都在下降到某个节点姿态loss每隔几个batch就跳涨一次质量loss勉强下降最终验证集SROCC比单任务低不少。原因两个任务的梯度在共享层出现冲突尤其是“大角度但清晰”和“正面但模糊”这类样本姿态和质量目标本质上存在矛盾。如果loss权重不做归一化后段训练会被量级更大的任务主导。解决按单任务baseline设置初始alpha再每隔5个epoch记录一次两个loss。如果某个任务持续高于下限10%以上单独调这个任务的权重同时加上梯度裁剪避免单个冲突batch把共享层参数推偏。5.3 训练到一半loss变成NaN现象训练正常跑了几百个iteration后loss突然变成NaN重新加载checkpoint恢复训练很快又在同一位置附近崩溃。原因多为学习率过大导致梯度爆炸或者batch里出现纯黑边/全白图像。人脸检测裁剪时如果目标在画面边缘补边会引入大片零值区域这些区域的卷积输出容易被BN放大。解决先把学习率降到1e-4以下再看数据加载部分。对检测框做边界截断而不是补零避免生成纯黑边图如果一定要补边把补边改成均值像素填充并在数据增强时对补边区域做mask。检查是否NaN可以在backward前打印梯度norm如果norm超过几百就手动跳过这个batch。5.4 输出质量分全部集中在7~10分现象模型测试时对模糊、噪声严重的图也打出8分整个验证集预测分布偏向高分低分段几乎没有样本。原因训练集本身正样本多、坏样本少模型发现输出高分能覆盖大部分样本的loss低分样本对整个batch的贡献太小等于被淹没了。解决按质量分数重采样在dataloader里让低分段样本占比不低于20%同时把label做非线性拉伸从数据层面把低分样本的梯度差异放大。只调loss权重不动数据分布这个问题很难彻底解决。5.5 输入从224降到128后效果反而变差现象明明128更贴合人脸检测框训练后SROCC反而比224版本低2~3个点。原因一方面128分辨率丢弃了许多高频纹理轻微失真的区分度下降另一方面预训练权重在224上训练直接换到128后BatchNorm的统计量需要重新适应如果训练epoch不足模型还没稳定就被拿去做测试了。解决小分辨率模型要训练更久尤其是前10个epoch让BN重新统计如果分辨率已经偏低可以把backbone第一层stride从2改成1保留更多空间信息。同时测试时不要用resize到128的方式去评估应该把检测框裁剪后保持原分辨率送入网络让模型自己适应目标尺度。6. 进阶验证加载checkpoint快速复现用SROCC评估排序能力并自定义label拉伸训练结束后怎么验证模型真的有效我建议按三个步骤来先加载现成checkpoint跑通推理再用SROCC评估排序能力最后根据业务数据调整质量分label的拉伸参数。先加载checkpoint。这份资源里保留的checkpoint就是干这个用的假设你的训练脚本把权重存到了checkpoint目录下。加载128输入的模型时注意state_dict里的键名要和网络定义一致避免backbone与classifier重名冲突。import torch from src.model import create_model model create_model(input_size128) ckpt torch.load(checkpoint/best_quality.pth, map_locationcpu) model.load_state_dict(ckpt[state_dict]) model.eval()如果加载时报unexpected key最常见原因是之前用DataParallel训练权重键名带module.前缀。去掉前缀再load即可。这类模型实测时我会把输出分经过一个0~10的clip避免个别极端样本输出负分或超过10。第二步是评估排序能力。质量评价领域最常用的指标是SROCC即Spearman秩相关它检查的是模型预测分数和真实label之间的排序一致性这正好对应Rank阶段的目标。from scipy.stats import spearmanr preds [model(x).item() for x in test_loader] labels [label for _, label in test_loader] srocc spearmanr(preds, labels).correlation print(fSROCC: {srocc:.4f})SROCC只看排序不要求绝对分数精确。如果SROCC比较高但MAE很大说明模型排序正确但标定不准可以加一个线性回归把输出映射到目标区间。相反如果SROCC不高但MAE还行说明模型在打安全牌把所有样本都预测到均值附近这种情况在实际业务中不可用。第三步是label非线性拉伸。对质量label做拉伸实际上是把原始1到5分的标度映射到0到10低分段用子线性映射放大差异。核心是gamma参数gamma小于1会让低分段的斜率更大。def map_quality(raw, src_max5.0, dst_max10.0, gamma0.6): norm max(raw, 0.0) / src_max norm pow(norm, gamma) return dst_max * norm比如原始0.5分线性映射大概是1分gamma取0.6后0.5/50.10.1^0.6≈0.398映射到3.98分。这样低分图像在0~4区间内的差异被明显放大训练时低分段梯度占比更高。但gamma不宜太小否则0分附近会无限接近0高分也全挤在9分以上。我一般先用0.6根据低分段SROCC再调如果低分段还是拉不开就降到0.5。我犯过的比较蠢的错是最初只看PLCC调模型把每个batch的MAE训练得特别漂亮结果SROCC一直上不去因为模型把所有模糊程度不同的图都打了接近同一档的低分。从那以后我每次训练完都会把预测和真实label打散成散点图再算一遍SROCC顺手挑几对“低分图到底比高分图差在哪”人工看一眼。希望这个验证流程能帮到你。本文还有配套的精品资源点击获取
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

汽车电子底层软件开发:AUTOSAR与CAN总线实战解析 2026/9/24 23:59:54

汽车电子底层软件开发:AUTOSAR与CAN总线实战解析

1. 这门“汽车电子底层软件开发就业课”到底在教什么?——不是写个LED闪烁就能上岗的很多人看到“汽车电子底层软件开发就业课”这个标题,第一反应是:不就是嵌入式C语言单片机CAN通信?刷几道LeetCode、调通一个STM32 CAN收发例程&…

阅读更多 →
Vim基础操作全攻略:保存退出、模式切换与高频命令实战 2026/9/24 23:59:54

Vim基础操作全攻略:保存退出、模式切换与高频命令实战

1. 项目概述1.1 核心需求解析今天聊聊Vim。写这个题目的原因是:几乎每个后端开发者、运维人员、数据工程师某天都会遇到一个场景——深夜加班,服务器登录界面只有黑底白字,编辑器只有vi/vim,你必须在五分钟内完成一次配置修改并保…

阅读更多 →
Python+CNN车牌识别实战:从数据预处理到模型训练与部署 2026/9/24 23:59:54

Python+CNN车牌识别实战:从数据预处理到模型训练与部署

简介:基于Python与卷积神经网络的车牌识别项目,面向计算机视觉初学者及智能交通开发者,目标是帮助用户掌握从数据预处理、模型构建到实际部署的完整流程。压缩包共25个文件,包含jpg/png图像样本、py训练脚本、md说明文档、dat数据…

阅读更多 →
AI元人文:从工具使用到思维重构的深度探索 2026/9/24 23:59:54

AI元人文:从工具使用到思维重构的深度探索

最近半年我一直在琢磨一件事:AI元人文到底是什么?说白了,就是“用元视角重新审视人与AI的关系”,也在“探索AI如何反向逼着我们发现自己的思考边界”。标题里的“元探索”,在我看就是一层套一层的追问——当你用AI解决…

阅读更多 →
《AI Agent 场景应用 - MobileOpenClaw》第5-9节:会话上下文细化处理实战指南 2026/9/24 23:59:47

《AI Agent 场景应用 - MobileOpenClaw》第5-9节:会话上下文细化处理实战指南

文档教程后端 【免费下载链接】CodeGuide :books: 本代码库是作者小傅哥多年从事一线互联网 Java 开发的学习历程技术汇总,旨在为大家提供一个清晰详细的学习教程,侧重点更倾向编写Java核心内容。如果本仓库能为您提供帮助,请给予支持(关注、…

阅读更多 →
写出来的,和没写的——七个模块,一副骨头 2026/9/24 23:59:47

写出来的,和没写的——七个模块,一副骨头

「合金日记」第 85 篇 「小艾说」第 34 期 幕后弧(换弧开篇) 从「写谁」转向「怎么写」 专栏连载中 前篇:《听漏了,还是听深了——一个 a,一句禅》 模块 骨架 沉默 对位 骨头 没看过前篇也能读 没看过前八十…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞