ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

YOLOv8舌象智能诊断实战:从数据标注到Python服务部署

YOLOv8舌象智能诊断实战:从数据标注到Python服务部署 简介面向毕业设计与课程实践的舌象智能诊断系统基于YOLOv深度学习框架与Python语言构建定位为可运行、可扩展的完整项目方案兼顾医学教学演示、科研分析与基层辅助诊断场景。整套资源共221个文件压缩包约42.76MB主要包含54个Python源码文件、61张标注图片、配套模型权重备份zbak及训练配置文件json/txt另有界面ui、说明文档与图表源码注释完整便于初学者按模块拆解学习。系统覆盖图像采集、特征提取、模型训练与结果分析全流程预处理环节加入光照补偿与色彩校正模型可识别舌体轮廓与舌苔分布并支持批量处理、可视化报告及多用户权限管理。当前已有67人学习适合需要在真实数据上完成深度学习落地项目的读者。1. 舌象智能诊断系统在做什么从一张舌照片到一份结构化报告中间隔着三道坎中医望诊里舌诊是最典型的那个“黑匣子”——同一张舌照片不同医生看结论经常差出级别。舌象智能诊断系统要干的事就是用 YOLOv 深度学习目标检测加 Python 服务把“看舌头”从主观经验变成可复现的量化流程先自动定位舌头区域再判断舌色、苔色、苔质最后输出结构化报告。这套方案适合两类人想拿医学图像做一个完整落地项目的开发者以及中医信息化团队在正式立项前先搭的验证原型。标题里带完整源码与数据集意味着不用从零攒数据可以直接在已有基础上复现和二次改造。真做起来你会发现卡点不在模型结构而在数据采集规范和标注一致性下面按数据、训练、服务、排错的顺序逐个说透。2. 为什么舌象检测选YOLOv任务特殊性、选型理由与数据集的三步准备在一个中医影像项目立项前很多人第一句话就问“用语义分割还是目标检测”。我的答案取决于输出需求系统最终要把舌体区域交给后续诊断模块矩形检测框已经足够不需要像素级的轮廓。舌诊照片的来源是手机或诊室相机画面里除了舌头还有面部、口腔、反光检测模块要做的事就是“把舌头框出来”而不是做一次精细的图像分割。2.1 舌象目标检测任务与通用检测的区别舌头不是刚性目标伸舌力度不同长度、宽窄、弯曲度都会变舌体周边还跟着嘴唇、牙齿、硬腭色域与皮肤高度重叠。通用检测里常见的“颜色即特征”在这里失效模型必须学的是舌面纹理、舌尖形态、舌根与咽喉交接处的结构。这就决定了选型标准第一单阶段模型优先因为业务最终要实时预览给用户看取景框第二模型要能扛住小样本迁移因为真实舌象集规模有限第三输出要有再工程化的余地不能只给一个类别名。在YOLOv系列里我一般以YOLOv8作为默认起点。原因很具体v8改成anchor-free之后解除了anchor尺寸和长宽比这一组超参数舌体形态变化大手工调anchor本来就是玄学其次ultralytics的接口把这部分统一了训练、验证、导出ONNX都在一个Python API里完成服务端工程化顺滑许多。对比Faster R-CNNv8在同类硬件上推理速度能快一个量级精度在舌象这种中尺度目标上差距很小。对比Mask R-CNN这类实例分割模型舌象诊断的下一步是裁剪区域的颜色与纹理分析矩形四角之外的像素对诊断没有增量价值分割模型多出的标注成本、显存成本都不划算。要守住一个原则先验证业务闭环再往上堆复杂度。2.2 数据集来源、隐私规范与按患者划分的脚本舌象数据集的现状是公开的学术舌象集数量不多标注维度集中在舌色、苔色这类分类标签检测框往往要自己补标医院门诊自采数据质量好但涉及个人健康信息采集前要明确脱敏方式和使用边界。常见做法是公开集打底、自采集调优因此数据整理流程必须从第一天就规范。命名规范我固定用patientID_sessionID_shotID三段式比如p003_s01_002.jpg后面所有脚本都靠这个命名解析患者维度。划分训练集与验证集时必须按患者分组不能按图片随机打散——同一个人的几十张照片高度相似按图随机划分会把验证集泄漏到训练集里得出的mAP是个假象。# scripts/split_dataset.py # 按患者维度划分训练/验证集避免同一患者照片同时出现在两侧 import os import random from collections import defaultdict from pathlib import Path random.seed(2024) IMG_ROOT Path(datasets/tongue/images/all) # 原始图片目录 SAVE_ROOT Path(datasets/tongue/images) # 划分后输出目录 TRAIN_RATIO 0.8 patient_map defaultdict(list) for img_path in IMG_ROOT.glob(*.jpg): # 文件名约定p003_s01_002.jpg第一段是患者id parts img_path.stem.split(_) patient_map[parts[0]].append(img_path) patients list(patient_map.keys()) random.shuffle(patients) train_patients set(patients[:int(len(patients) * TRAIN_RATIO)]) for patient, img_list in patient_map.items(): dest train if patient in train_patients else val (SAVE_ROOT / dest).mkdir(parentsTrue, exist_okTrue) for src in img_list: # 用软链接避免复制大体积jpg占双倍磁盘 os.symlink(src, SAVE_ROOT / dest / src.name)这段脚本的逻辑是把患者作为随机单元而不是把图片作为随机单元。random.seed(2024)保证同一批数据在多次执行时划分结果一致方便对比不同训练配置用os.symlink而不是shutil.copy是为了避免好几万张JPG在磁盘上重复占空间。划分完成后建议再跑一次重复检查用感知哈希对比训练集验证集图像的相似度把相似度超过阈值的样本标记出来人工确认这一步能救回不少后续评估时的信誉。2.3 标注格式转换与可视化质检手工标注阶段用的工具基本还是LabelImg它导出的默认格式是Pascal VOC XML而YOLOv8训练读的是每张图一个txt的YOLO格式。下面这个脚本负责把XML统一转为txt# scripts/voc2yolo.py # 把LabelImg导出的VOC XML标注转换为YOLO训练的txt标注 import xml.etree.ElementTree as ET from pathlib import Path def voc_to_yolo(xml_path: Path, out_dir: Path): tree ET.parse(xml_path) root tree.getroot() size root.find(size) W int(size.find(width).text) H int(size.find(height).text) lines [] for obj in root.findall(object): name obj.find(name).text if name ! tongue: # 舌象检测只保留舌体这一个类 continue box obj.find(bndbox) x1 float(box.find(xmin).text) y1 float(box.find(ymin).text) x2 float(box.find(xmax).text) y2 float(box.find(ymax).text) # YOLO格式class cx cy w h全部除以图宽高做归一化 cx (x1 x2) / 2 / W cy (y1 y2) / 2 / H w (x2 - x1) / W h (y2 - y1) / H lines.append(f0 {cx:.6f} {cy:.6f} {w:.6f} {h:.6f}) out_dir.mkdir(parentsTrue, exist_okTrue) (out_dir / (xml_path.stem .txt)).write_text(\n.join(lines)) # 用法遍历标注目录逐个调用上方函数 for xml_file in Path(datasets/tongue/labels_xml).glob(*.xml): voc_to_yolo(xml_file, Path(datasets/tongue/labels_yolo))这里有几个容易翻车的点VOC坐标是像素值而YOLO需要归一化后的0到1浮点直接用原值训练会出问题XML里如果混入了LabelImg预置的其他类别而没有过滤转换后会把背景当成目标。转换完成后还要随机抽二十张图把检测框画回原图检查# scripts/vis_labels.py # 把txt标注画回原图人工检查框是否贴合舌尖与舌根 import cv2 img cv2.imread(datasets/tongue/images/train/p003_s01_002.jpg) h, w img.shape[:2] for line in open(datasets/tongue/labels_yolo/p003_s01_002.txt): _, cx, cy, bw, bh map(float, line.split()) x1 int((cx - bw / 2) * w); y1 int((cy - bh / 2) * h) x2 int((cx bw / 2) * w); y2 int((cy bh / 2) * h) cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2) cv2.imwrite(vis_p003_s01_002.jpg, img)画框检查的重点不是“框得准不准”而是有没有把下唇、牙龈包进来。舌体和嘴唇同色域标框的人手一抖把下唇框进去模型学到的模式里就混入了“唇部开口”特征推理时自然就会连带框出别人的嘴唇。质检通过后再进入训练环节否则训练两小时、排错一整天都是这里省下的功夫在后面加倍补交。3. 用YOLOv8训练自己的舌象数据集环境、最小命令与增强参数调优数据质检通过之后代码部分就顺畅了。训练阶段的目标不是把模型调到最极致而是让团队里每个成员都能用一套固定命令复现训练过程。下面先从环境与最小训练命令讲起再展开针对舌象的增强参数定制。3.1 环境搭建与一次训练的最小命令环境按官方文档装即可Python 3.10以上准备好CUDA和对应驱动。安装依赖只用一行命令但要装到专门的虚拟环境里不要直接打入系统Python否则后面的OpenCV和ultralytics版本冲突会让你怀疑人生。常见做法是conda建一个新环境然后pip install ultralytics opencv-python。训练入口是两个文件一个描述数据集的YAML一个Python脚本。YAML内容如下# datasets/tongue/tongue.yaml path: /home/yourname/datasets/tongue # 改成你机器上的绝对路径 train: images/train val: images/val names: 0: tongueYAML里唯一需要小心的是path这个字段它要求是绝对路径。用相对路径时换一台机器整个路径就断了训练报错会很奇怪。train和val是相对path的子目录这里直接指向划分好的两个图片目录。训练脚本可以很短# scripts/train_tongue.py from ultralytics import YOLO # 用coco预训练权重初始化再在自己的舌象数据上微调 model YOLO(yolov8n.pt) model.train( datadatasets/tongue/tongue.yaml, epochs120, # 数据量小epoch设多些配合早停 imgsz640, # 训练分辨率先跑小尺寸验证流程 batch16, # 单卡常见配置显存不够就降到8 device0, # 使用GPU没有GPU时写cpu但速度慢一个量级 patience20, # 验证指标连续20个epoch不涨就停 )这段代码的imgsz值得多说一句。手机原图经常是3000x4000级别直接跑960分辨率会占用大量显存先用640把流程跑通再提高分辨率看收益是稳妥路径。舌象的舌乳头等细纹理在640下会损失一部分如果后续诊断对纹理敏感再升到960。训练结束后runs/detect/train/weights/下会同时出现best.pt和last.pt前者是验证集指标最优的权重后者是最后一个epoch的实时权重。3.2 舌象训练的四个关键增强超参第一次跑通之后真正让模型在不同光源、不同手机下都能可用的是数据增强参数。通用数据集上默认的一整套增强在舌象上可能帮倒忙。下面这组配置是我在舌象项目上反复试出来的起点# scripts/train_tongue_advanced.py from ultralytics import YOLO model YOLO(yolov8n.pt) model.train( datadatasets/tongue/tongue.yaml, epochs150, imgsz960, # 提升分辨率保留舌体纹理细节 batch8, # 分辨率翻倍batch要相应减半 mosaic0.3, # 舌象拼接增强意义不大降到0.3减少误学 close_mosaic10, # 最后10个epoch关掉mosaic让模型回归真实布局 hsv_h0.03, # 色相扰动要小过大把淡红舌增强成红舌 hsv_v0.6, # 亮度扰动加大提升对不同光源的适应力 fliplr0.5, # 舌体左右基本对称水平翻转是安全增强 scale0.3, # 缩放幅度控制住舌体宽窄比例不能学歪 optimizerAdamW, lr01e-3, )逐项解释这些参数。mosaic是Ultralytics默认最强的一档增强把四张图拼成一张对目标小、背景杂的场景有效但舌象样本本身就带结构性四张舌头拼在一起会让模型学到“舌体可以以奇怪的方式拼接”的错误先验降低到0.3即可。close_mosaic10让最后十个epoch彻底关闭拼接让模型在真实布局上收尾这是缓解增强与真实分布不一致的常用手段。hsv_h只给0.03舌色之间的界限本来就细色相扰动过大等于人为制造标签噪声。hsv_v0.6是这组参数里最重要的舌象照片在不同光源下的亮度差异远大于色相差异把亮度扰动拉高模型才不会死记“舌头就应该是这个亮度”。如果不确定参数怎么调先全部用默认跑一个baseline再逐个参数改不要让两个以上参数同时变否则出了问题根本定位不到是哪个增强引入的。3.3 评估指标怎么读怎么导出部署格式训练结束后的评估不要只看最终那张图。Ultralytics会在runs/detect/train/下生成results.csv我一般直接打开看最后几十行的metrics/mAP50(B)和metrics/mAP50-95(B)。对舌象检测来说mAP50到0.9以上不算难因为舌头是画面里的大目标真正能暴露问题的是mAP50-95它对框的贴合程度非常敏感这个值低说明框要么偏大要么偏小裁剪出来的区域会带着嘴唇或者切掉舌尖。业务上更实用的评估口径是“裁剪保留率”对每张验证图检查预测框内部有多少比例的舌体真值被覆盖这个指标直接决定了后续诊断模块拿到的区域干不干净。导出部署格式的代码是同一套API# scripts/export_onnx.py from ultralytics import YOLO model YOLO(runs/detect/train/weights/best.pt) model.export( formatonnx, dynamicTrue, # 支持动态batch服务端并发更灵活 imgsz640, halfTrue, # FP16精度GPU推理更快CPU环境把half去掉 simplifyTrue, # 简化计算图减少算子兼容问题 )导出完成后强烈建议做一次“同一张图、两种格式”的对比把predict结果里的框坐标分别用pt和onnx跑一遍检查坐标差是否在1个像素以内。ONNX转换偶尔会丢算子或精度抖动直接拿到生产环境推理翻车时排查成本高得多。这一步属于十分钟能做完、能省一晚上排错的操作值得写进团队的发布流程。4. 用Python把模型变成舌象诊断服务FastAPI接口与诊断规则管线训练好的权重只是“能看到舌头”的检测模型离诊断系统还差两层一层是外部用户能调用的服务接口另一层是把检测框转换成舌色、苔色诊断结论的业务逻辑。这一章把它做成最小可用的工程结构。4.1 最小可用检测接口一次加载、多请求复用服务端用FastAPI原因很朴素它自带请求校验和OpenAPI文档前端联调的时候直接看/docs页面就能试接口省去手写接口说明。核心代码量不大# app/main.py import cv2 import numpy as np from pathlib import Path from fastapi import FastAPI, UploadFile from ultralytics import YOLO app FastAPI() # 进程启动时加载一次不要在请求处理函数里重复加载权重 model YOLO(weights/best.pt) device cuda:0 if __import__(torch).cuda.is_available() else cpu app.post(/detect) async def detect(file: UploadFile): content await file.read() img_array np.asarray(bytearray(content), dtypenp.uint8) # 内存解码避免把临时文件写到磁盘再读 img cv2.imdecode(img_array, cv2.IMREAD_COLOR) if img is None: return {code: 1, msg: image decode failed} results model.predict( sourceimg, imgsz960, conf0.5, # 舌象是中等目标阈值太高容易漏检 iou0.6, devicedevice, verboseFalse, ) boxes results[0].boxes.xyxy.cpu().numpy().tolist() confs results[0].boxes.conf.cpu().numpy().tolist() return {code: 0, boxes: boxes, confs: confs} if __name__ __main__: import uvicorn uvicorn.run(app, host0.0.0.0, port8000)两个细节解释一下。第一model必须在模块加载时初始化如果每次请求都重新加载几百毫秒的加载耗时会让接口响应时间飙到秒级并发一上来机器直接卡死。第二imgsz960要和训练时的分辨率保持一致推理分辨率突然改变检测框的质量都会下降。conf0.5是一个折中值舌象检测对漏检更敏感宁可偶尔多一个误检框也不能把真舌头丢了业务侧可以通过置信度排序做二次过滤。4.2 从检测框到诊断结论先搭规则管线再换分类模型拿到检测框后诊断模块的第一步是裁剪舌体区域。裁剪时我习惯向外扩10%因为检测框通常贴合舌尖和舌根直接裁剪可能把边缘部分切掉外扩能保留下颌组织与舌根的过渡带# app/diagnose.py import cv2 import numpy as np def crop_tongue(img, box, expand0.1): x1, y1, x2, y2 [int(v) for v in box] w, h x2 - x1, y2 - y1 x1 max(0, int(x1 - w * expand)) y1 max(0, int(y1 - h * expand)) x2 min(img.shape[1], int(x2 w * expand)) y2 min(img.shape[0], int(y2 h * expand)) return img[y1:y2, x1:x2] def tongue_color_rule(roi): 简单规则基线用HSV空间像素占比近似判断舌色正式项目会换成分类模型。 hsv cv2.cvtColor(roi, cv2.COLOR_BGR2HSV) H, S, V hsv[:, :, 0], hsv[:, :, 1], hsv[:, :, 2] # 淡白/淡红整体高亮、低饱和 pale_ratio float(np.mean((V 180) (S 90))) # 红舌红色调像素占比高 red_ratio float(np.mean(((H 10) | (H 170)) (S 60) (V 60))) if pale_ratio 0.5: return 淡白舌 if red_ratio 0.6: return 红舌 return 淡红舌这块必须把话说清楚HSV阈值规则只是用来快速跑通闭环的基线在受控光源下能把“淡红/红/淡白”分开自然光下很容易翻车。正式版本用两级架构YOLOv负责定位裁剪后的舌体图送入一个三分类或四分类的轻量模型标签由医生标注的舌色、苔色、苔质组成。规则管线的价值在于它让系统的接口、数据流、报告结构先定型后续替换分类模型时/detect接口不需要动只有tongue_color_rule内部实现被替换这种隔离在工程上很值钱。诊断输出建议直接返回结构化JSON同时加一句免责说明{ image_id: p003_s01_002, tongue_color: 淡红舌, coating_color: 白苔, coating_texture: 薄苔, confidence: 0.87, note: 仅供参考不作为医疗诊断依据 }苔色和苔质如果暂时没有分类模型可以用同一套规则管线先给出“白苔/黄苔”“薄苔/厚苔”的粗略判断注意在文档里标注这些字段当前是规则输出、准确性有限避免用户误读。4.3 源码组织的几个习惯训练、权重、数据三者分离一个含完整源码与数据集的项目最容易踩的坑是“所有文件堆在一个目录里”。我自己的目录结构固定如下tongue_diag/ ├── app/ │ ├── main.py # FastAPI服务入口 │ ├── detect.py # YOLOv8检测封装 │ └── diagnose.py # 诊断规则管线 ├── scripts/ # 数据集划分、格式转换、评估脚本 ├── weights/ # best.pt小体积、不入git ├── datasets/tongue/ # 原始数据与划分后的数据 └── requirements.txt # 锁定关键依赖版本这里有几个配套习惯weights和datasets不要提交到代码仓库训练权重动辄几十上百MB数据集又是敏感健康数据仓库只保留能从头复现训练过程的代码和说明requirements.txt要精确锁住ultralytics的版本不同主版本之间的参数兼容性差异足以让同一份代码在另一台机器上报出完全不认识的关键字错误。写README时把“跑训练”“跑服务”“重新生成数据划分”三条命令各写一行后面接手的人不用翻代码也能把环境搭起来。5. 舌象诊断系统的踩坑实录从训练到演示五条血泪经验训练、服务都能跑通之后真正的挑战才刚开始。下面是按真实频率排序的五条踩坑记录每条都按现象、原因、解决写清楚。5.1 换个房间检测框还在诊断结论却翻车了现象demo 时同一个受试者在窗边自然光下判断为“淡红舌”移到LED灯下变成“红舌”再换到诊室灯管下又变成“淡白舌”检测框每一张都框得准但颜色判断来回跳。 原因诊断规则管线直接消费BGR像素没有做白平衡和亮度校正训练图像的亮度分布太单一模型把“某个固定亮度”当成了舌色特征的一部分。 解决采集阶段固定光源或让标准色卡入镜推理阶段用OpenCV的白平衡算法先校正一张图训练阶段把hsv_v增强参数拉高到0.6左右让模型不再依赖绝对亮度。这个分层修法执行到位之后同类翻车基本不再出现。5.2 训练指标mAP 0.93部署到门诊手机漏检一半现象本地测试集指标很漂亮验证集mAP50超过0.9但把模型部署到门诊拍摄的手机图上漏检率肉眼可见地高。 原因数据集划分是按图片随机打散的同一个患者的几十张高度相似照片同时出现在训练集和验证集验证指标是被这个泄漏撑起来的假象是个黑匣子。 解决回到数据划分这一步按患者分组划分同时用感知哈希把训练集和验证集做重复度检查把相似度超过阈值的样本挑出来人工复核。这两步做完模型的真实水平才会原形毕露后续调优才有意义。5.3 训练一百个epoch输出永远只有“薄白苔”现象不管输入什么舌头报告里苔质永远是“薄苔”苔色永远是“白苔”分类准确率看着还挺高。 原因训练集里薄白苔占了七成以上分类模型学到的是“无脑预测多数类期望损失最低”的最优解宏观指标被样本分布灌水了。 解决一是在数据层面按类别做重采样或给loss加权重二是把舌色、苔色、苔质拆成独立的子模型分别训练不要再塞进同一个多分类头三是苔质这类细粒度属性可以用检测框内纹理区域的统计特征辅助判断降低模型对多数类的路径依赖。5.4 训练到一半显存OOM没有后悔药只能从头再来现象epoch跑到40多CUDA out of memory之前的训练进度全部作废重启后要么调小batch重跑要么干脆不知道从哪个权重继续。 原因先是batch size设置得碰运气其次是mosaic增强在epoch后段仍然开着某几个batch的拼接尺寸特别大内存峰值直接顶爆还有就是不熟悉last.pt的作用。 解决显存吃紧时先把batch减半再考虑降低imgsz在高版本ultralytics上使用close_mosaic10让最后10个epoch关掉拼接养成每个实验跑完就把runs目录备份的习惯续训时model.train(resumeTrue)直接接上last.pt这个后悔药能省掉一整晚重训时间。5.5 中文文件名和透明PNG让训练集悄悄缩水现象数据里有一批“舌象_白苔_003.jpg”训练日志没有error只有warn但训练过程结束后发现参与训练的样本数比预期少了几百张。 原因OpenCV的imread函数对中文路径支持不完善读不出来的图片返回None但没有抛异常另一个坑是RGBA的PNG被当成三通道读取透明区域变成黑色背景悄悄污染了样本分布。 解决图片在进数据集之前统一重命名为英文加数字读图后立即检查img is None为空的直接raise让训练停止而不是默默跳过PNG用cv2.IMREAD_UNCHANGED读入再转RGB合并白底。这些检查写进数据质检脚本就不会再发生“少了几百张图但没人知道”的事情。6. 系统跑通后先别急着演示混淆矩阵与色卡校准这两个验证技巧模型训练完、服务也通了先别急着向业务方演示。我有两个习惯性验证动作能在十分钟内暴露系统最不靠谱的环节。6.1 用混淆矩阵找出“最难分开的那一对标签”舌色分类里最尴尬的不是谁对谁错而是红舌和绛红舌、白苔和薄苔这种相邻标签之间反复纠缠。只盯着准确率根本看不到这种纠缠要看混淆矩阵。用医生标注的标签和系统输出各拉一列一行代码就能画出来# scripts/eval_confusion.py from sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay import matplotlib.pyplot as plt y_true [...] # 医生标注的舌色标签 y_pred [...] # 系统输出的舌色标签 labels [淡白, 淡红, 红, 绛红] disp ConfusionMatrixDisplay( confusion_matrixconfusion_matrix(y_true, y_pred, labelslabels), display_labelslabels, ) disp.plot() plt.savefig(cm_tongue_color.png, dpi150)看这个矩阵有一个固定顺序先找对角线相邻的非零项比如“红”被大量判成“绛红”这说明数据里这两个类的样本边界本身模糊再找跨区域的大数值那基本是采集光源问题而不是模型问题。优先解决混淆最重的相邻对比盲目增加训练轮数有用得多。6.2 一套固定的色卡校准流程替代“换手机就换结果”不同手机拍照的白平衡策略差异很大同一部手机在不同光源下也有偏移。为了解决这个问题我在采集规范里强制要求画面边缘出现标准色卡推理时先检测色卡区域用它的白点做整图白平衡校正。OpenCV提供现成实现wb cv2.xphoto.createSimpleWB() img_balanced wb.balanceWhite(img)这行代码不复杂但前提是画面里有可参考的中性色区域。没有色卡时直接调用反而会把本就偏色的图像拉向另一个极端。固定色卡入镜、再校正、再送入诊断管线这一整套流程跑下来不同手机间的结果一致性才会有质的提升。我的习惯是每次拿到新设备先拍一组带色卡的样张过一遍全流程再谈调优。舌象诊断这类系统的难点不在模型而在数据和评估口径有没有被钉死把这两处校准做好后面的调优才有意义希望帮到你。本文还有配套的精品资源点击获取
返回列表