ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

图像分割实战:Python+OpenCV从阈值到K-Means与语义分割

图像分割实战:Python+OpenCV从阈值到K-Means与语义分割 简介一份基于Python实现的图像分割算法课程设计资源面向计算机视觉方向学生及Python开发者适合作期末项目或算法练手资源围绕阈值分割思路通过设定恰当阈值将每张图像划分为5070个区域并额外限制每个区域像素数量不少于50兼顾算法完整度与工程约束。压缩包内共45个文件、大小约1.38MB主要包含40张png图像原图与分割结果对比、2个Python源码文件分割主程序及精度评估脚本、1份docx课程设计报告及说明文档与许可证目录按代码、数据、标注和输出分层组织便于直接运行与二次修改目前已有1844人学习下载。从内容预览看报告与源码配套完整读者可对照文档理解阈值分割的参数设定与区域过滤逻辑也可借助评估脚本量化分割精度并能直接复现分割效果、省去数据准备无论是课程答辩还是入门图像分割这份资源都能帮助读者快速掌握从算法原理到结果分析的全过程。1. 图像分割又不只是把图片切块这份 Python 项目在解决什么图像分割是让程序对图像里的每个像素回答“我属于哪个目标”而不是像目标检测那样只给目标套个矩形框。用 Python 做这件事靠的是 OpenCV、NumPy、scikit-image 这类库先把图像变成矩阵再让算法在矩阵上做像素级分类。这份“基于Python实现图像分割算法.zip”里卷起的就是一条从阈值分割、聚类分割到语义分割模型训练与评估的完整链路。它适合两类人一类是刚学 Python、想从“会写循环”走到“能处理真实图像”的入门者另一类是手里攒了一批业务图医学切片、工业零件、卫星影像急着做像素级区分的工程师。读完你至少能把环境搭起来、把一个最小分割脚本跑通并且知道自己后面该往哪个方向调。2. 解压后先别急着训练环境搭建与项目结构里的三个隐藏坑图像分割项目的第一步不是读算法是先把 Python 环境收拾利索。我见过太多人拿到代码就 pip install 一把梭结果卡在 import cv2 报错、matplotlib 颜色不对、训练时环境依赖冲突这三大拦路虎上。这一章按“先看结构、再建环境、后验证”的顺序把这三个坑提前填上。2.1 压缩包里通常装了什么一个再小的图像分割项目文件结构也逃不开这么几块主入口脚本、算法模块、依赖清单、样例图像、输出目录和说明文档。哪怕作者没有写 README你也该在解压后第一时间摸清入口文件在哪。常见成员典型作用需要关注的点主程序如 segment.py命令行入口接收图像路径并输出分割结果确认它默认读图的路径是相对路径还是绝对路径算法模块封装阈值分割、聚类分割或网络模型看函数参数有没有写死图像尺寸requirements.txt锁定依赖库及其版本没有这个文件就得手动装依赖样例图片与标注用来验证算法效果的基准数据用它跑通全流程后再换自己的数据输出目录存放分割结果和可视化图代码里常会自动创建但有时需要手动先建我的习惯是先用两分钟看主程序的文件头和函数定义搞清楚作者预期的调用方式。这一步能省下后面一半的排错时间。很多翻车不是算法不行是你把一张三通道彩色图传进了一个只处理灰度图的入口。2.2 Python 环境和依赖安装为什么我坚持用虚拟环境python 安装本身不难难在装完之后不污染系统、不跟其他项目打架。我给这类图像分割项目建 Python 环境时不会把库直接装进全局环境而是用 venv 在项目目录里隔离出一个独立环境。这样即使同时维护三五个项目每个依赖互不干扰。# 用 Python 3.10 创建独立虚拟环境3.83.12 都稳妥 python3.10 -m venv .venv source .venv/bin/activate # Windows 下用 .venv\Scripts\activate # 图像分割项目最常用的一组依赖 pip install --upgrade pip pip install numpy opencv-python scikit-image scikit-learn matplotlib pillow # 验证关键库能否被正确导入 python -c import cv2, numpy, sklearn; print(cv2.__version__, numpy.__version__)虚拟环境的好处是“后悔药”装坏了直接删掉 .venv 重建不用动系统 Python。这里有几个参数和版本上的讲究。opencv-python 这个包是基于 pip 安装 OpenCV 的常见做法它自带 cv2 模块但注意它不包含需要专利许可的 contrib 模块如果你要用 SIFT 这类特征算子就得改成安装 opencv-contrib-python。scikit-image 提供分水岭、超级像素等分割算法sklearn 提供 KMeans 等聚类工具matplotlib 负责把结果画出来pillow 则用来读写 OpenCV 不擅长的图像格式。在 Linux 系统安装 python 之后还要确认 PATH 里能找到 pipWindows 上安装稍不留神就会漏掉“Add Python to PATH”导致命令行里 python 不是内部命令。每逢这种情况去系统环境变量里把 Python 安装目录和 Scripts 子目录补进 PATH 就能解决这是 python 环境变量配置最常见的动作。2.3 用最小命令验证环境import cv2 不报错才算起步依赖装完不等于万事大吉还要过一遍导入验证。上面那段命令里python -c 会把三个核心库一次性导入并打印版本号。这一行看起来简单但能暴露绝大多数环境问题如果打印出 cv2 的版本号说明 OpenCV 的 wheel 和你的 Python 版本匹配如果在虚拟环境里导入到了系统 Python 的包说明 activate 没生效如果直接报 ModuleNotFoundError大概率是这个环境的 pip 装到了别的 Python 解释器上。验证通过后我建议随手跑一个最小闭环读一张灰度图做一次 Otsu 阈值分割把结果保存到文件。这一步能确认 OpenCV 图像读写通道正常。注意这段验证代码里不要用 cv2.imshow因为很多服务器环境没有显示器imshow 会直接抛异常用 plt.savefig 把结果显示和保存拆开往后在无头环境下调试也不会被弹窗卡死。import cv2 import matplotlib.pyplot as plt # OpenCV 读图默认是 BGR 三通道先转灰度 img cv2.imread(data/demo.jpg, cv2.IMREAD_COLOR) gray cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 大津法自动算阈值不需要手动指定数值 _, binary cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY cv2.THRESH_OTSU) # matplotlib 显示单通道图必须显式指定 cmap否则默认伪彩色会误导你 plt.imshow(binary, cmapgray) plt.axis(off) plt.savefig(output/verify_otsu.png, dpi150, bbox_inchestight) print(环境验证通过分割结果已保存)这段代码里的 cv2.threshold 传的是 THRESH_BINARY 与 THRESH_OTSU 的按位或组合含义是“阈值由大津法自动计算二值化方式为常规黑白”。灰度转换这步很容易被忽略但如果不转灰度直接对三通道图做阈值程序不会报错只是每个通道各自二值化结果乱成一团。我这套环境建下来90% 的初学者问题都集中在 2.2 和 2.3 这两步所以不要急着往下跑网络训练。3. 把分割算法真正跑起来从 Otsu 到 K-Means 的最小可复现代码环境就绪后先别一头扎进深度学习。图像分割算法按复杂度分成几层每一层都有它适合的图像类型。选错算法不会报错但结果会诚实地告诉你“这条路不适合”。3.1 先分清楚你面对的是哪种图我一般把分割需求按图像特征分成三类。第一类是目标和背景灰度差异明显比如白底上的黑色零件用全局阈值分割就够了第二类是多个目标颜色不同但纹理相近比如区分图片里的橙色猫和棕色狗聚类分割更合适第三类是目标纹理复杂、与背景纠缠不清比如医学细胞切片或卫星影像里的房屋轮廓这时才轮到深度学习语义分割。判断依据很简单先用 OpenCV 读图、转灰度然后看一眼灰度直方图。如果直方图呈现双峰阈值分割大概率好用如果是多峰且峰之间彼此重叠直接上聚类或者网络模型。很多入门者拿到图就训 U-Net结果因为数据量不够效果还不如一个 K-Means这在图像分割入门阶段是非常常见的返工原因。3.2 Otsu 全局阈值一份可以直接复制的基线代码如果你确定了图像是前景背景分明Otsu 是成本最低的基线。它的原理是遍历所有可能的阈值找到让前景和背景类间方差最大的那个值本质是让分割后的两类“距离”最远。# segment_otsu.py —— 最小可复现的全局阈值分割 import cv2 import numpy as np import matplotlib.pyplot as plt def load_gray(path): # OpenCV 以 BGR 读入先转灰度再往下走 img cv2.imread(path, cv2.IMREAD_COLOR) if img is None: raise FileNotFoundError(f读不到图像: {path}) return cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) def segment_otsu(gray): # 第二个参数传 0 表示阈值由大津法给出这里的 0 只是占位 _, binary cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY cv2.THRESH_OTSU) return binary if __name__ __main__: import os os.makedirs(output, exist_okTrue) gray load_gray(data/demo.jpg) binary segment_otsu(gray) # 单通道图必须指定 cmapgray否则会显示成伪彩色 plt.subplot(1, 2, 1) plt.imshow(gray, cmapgray) plt.title(Grayscale) plt.axis(off) plt.subplot(1, 2, 2) plt.imshow(binary, cmapgray) plt.title(Otsu) plt.axis(off) plt.tight_layout() plt.savefig(output/otsu_result.png, dpi150) print(Otsu 分割完成查看 output/otsu_result.png)这段代码的逻辑是imread 读进 BGR 图cvtColor 转成单通道灰度threshold 在 THRESH_OTSU 标志下自动寻找最优阈值执行二值化。load_gray 函数做了两个防御动作——文件不存在时抛 FileNotFoundError而不是让后面的 cvtColor 报一个看不懂的 NoneType 错误。os.makedirs 加 exist_okTrue 是避免首次运行因为没有 output 目录而保存失败。参数上的关键点有四个一是 threshold 的第二个参数 0 在启用 Otsu 时会被忽略所以写什么值都行但别省。二是 THRESH_BINARY 和 THRESH_OTSU 必须用加号组合只用其中一个都不会触发自动阈值。三是 foreground 面积占比极小的情况下 Otsu 会把整张图都判成背景这时可以考虑改用自适应阈值或者把图像裁剪到目标区域再做。四是输出图用 savefig 而不是 imshow这样在无显示器的服务器上也能正常出图。3.3 K-Means 颜色聚类多目标分割时第一个该试的算法当图像里有多类目标、颜色差异明显阈值分割就力不从心了。常见做法是把每个像素的 RGB 值当成一个三维样本用 K-Means 把所有像素聚成 K 类再按聚类结果给像素重新着色。这个过程把图像分割转成了聚类问题是 sklearn 在图像任务里最典型的用法。# segment_kmeans.py —— 用颜色聚类做多目标分割 import cv2 import numpy as np from sklearn.cluster import KMeans def kmeans_segment(path, k3): # 注意 imread 只读图颜色转换要单独调用 cvtColor img_bgr cv2.imread(path) if img_bgr is None: raise FileNotFoundError(f读不到图像: {path}) img_rgb cv2.cvtColor(img_bgr, cv2.COLOR_BGR2RGB) h, w, c img_rgb.shape # 把二维图像展平成像素列表每一行是一个 RGB 样本 data img_rgb.reshape(-1, 3).astype(np.float32) / 255.0 # n_init10 避免随机初始化带来的局部最优random_state 保证可复现 km KMeans(n_clustersk, n_init10, random_state42) labels km.fit_predict(data) labels labels.reshape(h, w) # 用聚类中心颜色回填得到分割后的着色图 centers (km.cluster_centers_ * 255).astype(np.uint8) result centers[labels] return labels, result if __name__ __main__: import matplotlib.pyplot as plt import os os.makedirs(output, exist_okTrue) labels, result kmeans_segment(data/demo.jpg, k3) plt.imsave(output/kmeans_result.png, result) print(聚类中心颜色:, (km.cluster_centers_ * 255).astype(np.uint8))先声明一点这段代码里最后打印 km.cluster_centers_ 会报错因为 km 是函数内部变量不在全局作用域。要打印聚类中心应该在函数内 return 时把 km.cluster_centers_ 一起带出来或者把 KMeans 实例放到外面的作用域。这是一个非常容易在复制代码时踩到的低级错误我不会在正式代码里留这种暗坑——你只需要记住“函数内创建的对象在函数外直接用名字访问一定会 NameError”。正经说参数n_clusters 是 K 值也就是你希望把图像分成几块。K 值选多少不是靠猜常见做法是从 2 往上试观察分割结果的轮廓是否贴合目标边缘。n_init10 表示每个 K 值下跑 10 次初始化取代价最小的那次能有效降低随机性random_state42 则是给随机数生成器一个固定种子让你每次运行结果一致这在调参对比时非常重要。归一化那一步也值得注意RGB 三通道数值范围都在 0255直接做欧氏距离时每个通道权重相同归一化到 01 只是统一量纲真正要改权重时可以把色彩空间从 RGB 转到 LAB让亮度与颜色解耦聚类效果通常更好。3.4 深度学习分割网络在这条链路里的位置传统方法跑到这里只是基线。当图像噪声大、目标边缘模糊、光照不均匀时阈值和聚类都扛不住这时才轮到语义分割网络。最常见的一套做法是 U-Net 结构的编码器-解码器网络输入是归一化后的图像张量输出是每个像素的类别概率图最后用 argmax 取概率最大的类别作为分割结果。深度学习分割不是“模型越深越好”而是“数据标注质量决定上限”。如果前面传统方法能跑通说明你的图像质量足够好网络有机会学到稳定的特征如果传统方法都输出一团噪声就别指望网络凭空变出规则来。这也是我总把传统算法当试金石的原因——它们快、直观、能在五分钟内告诉你这份数据值不值得投入。4. 让算法适配你的数据标注转 mask 与四个必调参数跑通示例图像只是热身。真实项目里你一定会遇到两个问题自己的数据长什么样以及算法需要的数据格式是什么。这一章解决“从业务数据到算法输入”的最后一公里。4.1 为什么模型不差但效果差数据格式在撒谎图像分割模型训练时需要的不是矩形框而是一张和原图同尺寸的 mask 图。mask 里每个像素的灰度值对应该像素的类别编号0 是背景1 是第一类目标2 是第二类目标。很多人从标注工具里导出的是 COCO 风格的 JSON polygon 或 VOC 风格的 XML直接拿给模型训练当然报 shape 不匹配。这个阶段最常出问题的反而是肉眼看不出的格式细节mask 是单通道还是三通道、像素值是 0/1 还是 0/255、类别编号是否连续。OpenCV 读入 mask 时默认按三通道处理如果你的 mask 是 L 模式单通道 PNG直接 cv2.imread 会得到一个形状完全不对的数组程序不会报错但训练时 loss 会一直在高位震荡。4.2 把 COCO 风格标注转成训练要的 mask转换脚本与边界坑手工标注工具导出格式五花八门最常见的是 JSON 里存 polygon 顶点坐标。转换思路很简单读入坐标用多边形填充函数在空白图上画出来每个类别填一个不同的像素值。# json2mask.py —— 把多边形标注渲染成单通道 mask import json import numpy as np import cv2 from PIL import Image def polygon_to_mask(json_path, img_h, img_w, save_path): with open(json_path, r, encodingutf-8) as f: ann json.load(f) # 背景固定为 0每个目标类别从 1 开始编号 mask np.zeros((img_h, img_w), dtypenp.uint8) # 不同标注工具字段名不一样常见的是 polygon 或 points # 动手前先 print(json.dumps(ann, indent2)) 看真实结构 for cat_id, obj in enumerate(ann[objects], start1): pts np.array(obj[polygon], dtypenp.int32) # fillPoly 要求顶点排成 (N, 1, 2) 的形状这里直接传 (N, 2) 也能用 cv2.fillPoly(mask, [pts], colorcat_id) # L 模式存 PNG保证像素值不会被调色板改写 Image.fromarray(mask, modeL).save(save_path) return mask这段代码有三个边界坑。第一polygon 的字段名因标注工具而异有人叫 “polygon”有人叫 “points”还有人存的是 segmentation 下的嵌套列表。写通用脚本前先打印 JSON 结构看清一层套一层的数据形态再定解析逻辑。第二fillPoly 的第二个参数需要传入一个多边形列表每个多边形必须是 int32 类型浮点坐标会直接报 TypeError。第三mask 保存成 PNG 时务必用 L 模式如果你用 cv2.imwrite它会按 BGR 三通道把单通道数组重复成三份训练时如果没做通道压缩模型会把三份重复通道当成有效信息白白多算三倍参数。numpy 类型转换在这类脚本里非常频繁uint8 与 int64 混用会让 fillPoly 报错赋值前统一转 int32 是一项必须遵守的习惯。4.3 必调参数一颜色空间与归一化图像分割的输入预处理没有统一公式但我不建议直接把 BGR 图喂给模型。OpenCV 读进来的图是 BGR 顺序而大部分在 PyTorch 或 TensorFlow 上预训练过的模型期望的是 RGB。顺序颠倒不会让训练崩掉但会让模型学到的颜色特征和你预期对不上收敛速度明显变慢。归一化的方式也影响结果。常见做法是把像素值从 0255 缩放到 01再按数据集的均值标准差做标准化。如果只做 01 缩放模型的初始损失会比标准化后高不少因为输入分布和网络权重初始化时的假设不一致。另外有些分割场景下 RGB 不是最好的颜色空间——比如工业零件检测中光照不均转成 LAB 空间只取 L 通道做灰度分割往往比直接在 RGB 上硬扛更稳。怎么判断该不该换空间跑一个 Otsu 看直方图双峰不明显就试试 LAB 的 L 通道这个测试成本只要两分钟。4.4 必调参数二类别不平衡与 loss 选择分割项目里“背景远远多于前景”是常态一张 1024×1024 的图里目标区域可能只占 5%。这种比例下如果用标准交叉熵模型会倾向于把所有像素判成背景因为只要这么做loss 已经很低了。此时有两个调参方向一是换 loss把交叉熵换成 Dice loss 或 Focal loss让模型把注意力放到难以分类的少量像素上二是在采样阶段多裁包含目标的 patch这是数据层面的做法对任何 loss 都有效。学习率、batch size、epoch 这三个参数在分割项目里通常按经验起步学习率 1e-4 到 1e-3batch size 受显存限制但尽量不小于 4epoch 先用 50 轮看曲线。这些数字不是定理而是可复现的起点。每调一个参数固定其余所有条件只改这一个变量并把每次实验的指标记录下来否则就是在拿玄学调模型。5. 图像分割项目避坑指南5 个能让进度归零的真实故障下面五条来自我实际跑图像分割项目的血泪经验。每一条都按“现象 → 原因 → 解决”写你可以直接拿来做排查手册。5.1 import cv2 报错 DLL load failed现象pip 安装 opencv-python 后执行 import cv2 抛出 ImportError: DLL load failed程序直接退出。原因最常见的是 Python 版本与 OpenCV 预编译 wheel 不匹配。比如 Python 3.13 刚发布时OpenCV 官方还没有推出对应版本的 wheelpip 会尝试安装一个不兼容的旧版另外 Windows 环境下缺少 VC 2015-2022 运行库也会导致同样的报错。解决把 Python 换到 3.83.12 之间创建一个全新虚拟环境重新安装 opencv-pythonWindows 用户安装 Visual C Redistributable如果 conda 环境里安装优先用 conda-forge 渠道的 opencv因为 conda 会把依赖的运行库一并装好。5.2 matplotlib 里图像整体偏蓝偏红现象用 imshow 显示 OpenCV 读入的图人脸或天空的颜色明显失真整体呈蓝橙色。原因OpenCV 的 imread 默认读入 BGR 顺序而 matplotlib 的 imshow 按 RGB 顺序渲染通道顺序错位导致颜色完全错乱。这不是分割算法的错是读图与显示之间缺了一次颜色转换。解决imread 之后调用 cv2.cvtColor(img, cv2.COLOR_BGR2RGB)把顺序换回来再接 matplotlib。处理灰度图时imshow 必须指定 cmapgray否则会按默认 colormap 显示成伪彩色肉眼判断阈值效果时容易被误导。5.3 分割结果边缘全是锯齿和毛刺现象目标内部分割正确但轮廓凹凸不平甚至出现单像素的凸起和断口看起来像被啃过。原因一是标注阶段的 polygon 顶点太稀疏人工画的轮廓精度不够二是二值化结果直接输出没做后处理单个噪声像素也被保留下来三是 mask 在缩放或格式转换时被插值污染边界像素值变成了介于 0 和 1 之间的灰值。解决标注时加密顶点尤其是曲线区域二值化后做一次形态学开闭运算先用 open 去孤立点再用 close 补小洞kernel 大小从 3×3 起步mask 缩放时使用最近邻插值而不是双线性插值避免产生灰色边界像素。检查 mask 时可以用 np.unique 看像素值如果出现 0 和 255 之外的数值说明中间步骤把 mask 当普通图片处理了。5.4 Dice loss 停在 0.9 上下不再下降现象训练前十几个 epoch 指标上升很快然后长期停滞在 0.9 附近看起来已经很好了但可视化结果里小目标根本没被分割出来。原因Dice 系数对小目标非常敏感如果前景占比本身就小即使小目标完全漏检对整体指标的影响也很微弱损失曲线因此显得平坦。另一个隐藏原因是 mask 没有索引化标注里前景像素值是 255模型要预测的类别却只有 0 和 1数值范围不一致导致网络输出概率无法正确对齐标注。解决把 mask 里所有非零像素统一归一化为 1并用 np.unique 确认只有 0 和 1 两个值对小目标漏检的问题按类别分别计算 IoU单独看每一类的指标而不是只看均值如果小目标类别是关注重点改用 Tversky loss通过 alpha 和 beta 参数控制对漏检的惩罚权重。5.5 一张 4K 图就把 16G 内存吃穿现象对一张 4000×3000 的大图跑 K-Means 或送入语义分割模型内存占用瞬间飙升机器卡死。原因K-Means 要读入全图像素作为样本4000×3000 的 RGB 图就是 3600 万个三维样本fit 时要算全部样本与聚类中心的距离内存自然爆炸。语义分割网络同理直接整图前向计算占用的显存也远超预期。解决K-Means 场景先用 cv2.resize 把图像缩小到最长边 1000 像素左右聚类得到结果后再把标签图放大回原尺寸或者改用 sklearn 的 MiniBatchKMeans 分批拟合内存占用会降一个数量级深度模型推理时把大图切分成 512×512 的 patch分别推理后拼接回原图尺寸。拼接时相邻 patch 之间要多留 overlap 区域比如每家 64 像素推理后去掉边缘部分再拼可以避免切缝处出现明显的分割断层。6. 量化分割效果再收尾用 IoU、Dice 与可视化验证跑通算法只是开始分割做得好不好得拿数字说话不能只凭肉眼感觉。我的习惯是无论如何先算一组 IoU 和 Dice这两个指标几乎成了图像分割项目的事实标准。指标侧重什么时候优先看IoU同时惩罚多分割和漏分割目标尺度接近、背景占比适中时Dice对前景占比小的目标更稳目标只占图像几个百分点时像素准确率容易被背景主导容易虚高只做辅助参考不当主要指标def iou(pred_mask, gt_mask, eps1e-6): # 两个 mask 都必须是 0/1 二值如果是 0/255 先归一化 inter np.logical_and(pred_mask, gt_mask).sum() union np.logical_or(pred_mask, gt_mask).sum() return (inter eps) / (union eps) def dice(pred_mask, gt_mask, eps1e-6): inter np.logical_and(pred_mask, gt_mask).sum() return (2.0 * inter eps) / (pred_mask.sum() gt_mask.sum() eps)eps 是为了防止除零当两个 mask 都是全背景时iou 和 dice 会返回 1这在逻辑上不对但避免了程序崩溃。计算多类别时按类别分别计算再取平均比把所有像素混在一起算更有意义。默认输入的 mask 必须是 0/1如果直接用 0/255 的 mask 计算pred_mask.sum() 会把数值放大 255 倍算出来的指标完全失真。量化之后还要做可视化验证。我常用的做法是把 mask 半透明叠加在原图上mask 区域染一种颜色这样能直观看出分割边界和目标的贴合程度。如果画出来的结果里某些类别的 IoU 很高但视觉上边界偏移严重说明标注本身可能有偏差此时优先检查数据而不是继续调参。遇到一张图的横坐标如果是一段连续序列图像要展示分割效果随帧的变化记得把 xticks 隔几个点显示一个标签否则坐标轴会挤成一团这也是 python 画图时最容易被忽视的细节。这套“先算指标、再叠图对比”的流程我每次做分割项目都会先跑一遍。它最大的价值不是得出一个好看的分数而是逼你把预测结果和真实标注放到同一画布上对质所有问题都会在叠加图里现出原形。做图像分割踏实程度决定结果可靠程度希望这一整套从环境到评估的路径能帮到你。本文还有配套的精品资源点击获取
返回列表