ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

7820张建筑墙壁损伤数据:labelme转掩码训练避坑指南

7820张建筑墙壁损伤数据:labelme转掩码训练避坑指南

简介:面向建筑安全检测与计算机视觉研究人员,这份docx文档系统整理了建筑墙壁损伤缺陷分割数据集的完整规格。数据集包含7820张jpg图像及对应labelme格式json标注,覆盖20类常见损伤(如锈蚀、剥落、裂缝、排水问题、外露钢筋等),每张图像分辨率为640x640,标注均以多边形框形式精确勾勒缺陷区域。文档还统计了各类别标注数量,如锈蚀14665个、剥落9849个、空腔9222个等,便于用户了解数据分布。资源为单个docx文件,大小2.1MB,目前已有101人学习。借助文档可快速掌握labelme 5.5.0的标注查看与编辑方法,以及将json转换为mask/YOLO/COCO等格式的注意事项,为后续语义分割或实例分割任务提供可靠的数据基础。

1. 这套建筑墙壁损伤数据集,到底解决了什么

做建筑外观检测的同行拿到“建筑墙壁损伤缺陷分割数据集labelme格式7820张20类别.docx”这个标题时,第一反应通常是两类:要么觉得就是个普通标注数据包,要么被7820张的规模唬住。但真正用过建筑损伤数据的老手会知道,这个标题最值钱的信息藏在最后那个.docx里——它意味着这套数据附带一份中文项目说明文档,而不是像国外开源数据集那样甩个README就完事。墙壁损伤标注的难点不在画框,而在于裂缝、剥落、渗水、空鼓、泛碱这些缺陷的边界极不规则,标注工具和格式选错,后期做语义分割训练等于给自己挖坑。

这套数据采用的labelme格式,本质上是用JSON文件记录多边形顶点坐标。20个类别覆盖了建筑外墙常见的结构性损伤和表观缺陷,7820张的量级对语义分割任务来说,已经足够训练出一个能用的初版模型。这篇文章会把数据格式、转换脚本、训练接入和踩坑点一次性讲透,适合正在做建筑检测、土木视觉落地、或者想拿真实场景数据练手的算法工程师。

2. 先拆开标签看结构:labelme的JSON里存了什么,20类墙壁损伤怎么分布

2.1 一个labelme标注文件的核心字段

labelme生成的JSON虽然各家版本略有差异,但核心字段基本固定。拿到这套数据后,我建议你先别急着训练,先写几行代码把单个标注文件打开看结构。常见结构是:

{ "version": "5.8.3", "flags": {}, "shapes": [ { "label": "crack", "points": [[102.5, 340.2], [104.1, 330.8]], "group_id": null, "shape_type": "polygon", "flags": {} } ], "imagePath": "img_0001.jpg", "imageData": null }

注意几个关键点。imageData字段通常是为空或省略的,因为labelme在save时会默认把图片base64塞进去,但很多正式项目的标注配置会关掉这个选项以减小文件体积。这套数据集如果标注人员用了中文版labelme导出,version可能是5.8.3,而shape_type基本只会出现polygon一种——当然偶尔也混进矩形标注,后面讲转掩码时会单独处理。

points存的是多边形顶点坐标,顺序按标注时点击的先后排列。group_id在这个数据集里大概率是用不上的,它存在的意义是支持同一张图里多个实例的关联分组。但这里有个新手常犯的认知错误:labelme格式和COCO格式的本质区别在于,labelme没有独立的“实例编号”概念,一个多边形就是一个对象,后续转训练格式时如果遇到同一类别多个裂缝碎块叠加的情况,要自己做连通域合并或独立实例化处理。

2.2 20个类别该不该直接全量训练

标题说20类别,但实际做项目时,这20类里“裂缝”“渗水”“剥落”“泛碱”“空鼓”这几个大类可能占了九成样本,剩下的小类——比如“钢筋外露”“植物侵入”“涂鸦”“螺栓锈蚀”之类的边角类别,单类数量可能只有几十张。不做统计直接喂给分割网络,小类会被大类完全淹没。

我一般建议先跑一个类别数量分布脚本,把JSON文件夹扫一遍,统计每个label出现的图片次数和多边形个数。只有知道哪几个类是“长尾”,才知道后面要不要做类别加权loss、或者合并语义相近的类别。

import json import os from collections import Counter json_dir = "labels" shape_counter = Counter() image_counter = Counter() for name in os.listdir(json_dir): if not name.endswith(".json"): continue with open(os.path.join(json_dir, name), encoding="utf-8") as f: data = json.load(f) labels_in_image = set() for shape in data["shapes"]: shape_counter[shape["label"]] += 1 labels_in_image.add(shape["label"]) for label in labels_in_image: image_counter[label] += 1 print("多边形总数统计:", shape_counter.most_common()) print("出现图片数统计:", image_counter.most_common())

这段代码要注意两点。第一,encoding="utf-8"必须显式声明,因为这个数据集是按中文Windows环境制作的,JSON里如果含中文标签名,不声明编码很容易在Linux上直接解码失败。第二,词频统计用的是shape_counter和image_counter两个维度,一个反映标注工作量,一个反映类别覆盖率——有的类虽然多边形数量多,但集中在少数几张图上,这类就是典型的“单图多斑块”,模型很容易过拟合到那几张图的纹理上。

2.3 标签命名混乱是数据集的隐形雷

20个类别听起来规整,但用过真实数据集的人都知道,标注团队在不同批次产生的中文名/英文名混用、同义不同名才是常态。例如“裂缝”和“crack”、“墙皮剥落”和“spalling”可能同时存在。这套数据如果原始标签是中文的,后续训练前一定要做一次标签映射表,把所有变体统一到英文标签上。

映射做法很简单,我一般维护一个字典,把实际出现的所有标签名归并成标准类别:

label_mapping = { "裂缝": "crack", "crack": "crack", "裂纹": "crack", "墙皮剥落": "spalling", "剥落": "spalling", "spalling": "spalling", "渗水": "water_seepage", "泛碱": "efflorescence", }

然后再统一改写JSON文件里的label字段,备份原文件后再做覆盖写。这一步虽然单调,但如果跳过,后面的类别统计、训练权重、评估报告全都会被污染。检查是否存在一个标签的多个变体,建议直接列出所有distinct标签,人工过一眼,比写模糊匹配脚本更高效。

3. 把labelme JSON转成语义分割掩码:转换脚本与四个边界坑

3.1 为什么不能直接拿JSON喂给分割网络

语义分割网络输入的标签形式是掩码图,每个像素取值为类别编号,而labelme只记录了多边形的顶点坐标。必须通过polygon到mask的栅格化转换,把所有多边形填充到与原始图像同尺寸的单通道灰度图里。这张灰度图就是训练时要用的gt_mask:背景像素为0,第一个类别像素为1,依此类推。

转换工具有现成的labelme_utils,但我在实际项目里更倾向于自己写脚本,原因有二:一是labelme自带的转换脚本在Windows和Linux上行为略有差异,顶点坐标小数处理容易影响掩码边缘;二是自己写可以顺带处理类别映射和边缘防溢出。

我提供一个可直接使用的json_to_mask.py脚本,核心逻辑是根据原始图像尺寸创建空白掩码图,再用OpenCV的fillPoly对每个多边形填充类别编号:

import json import os import numpy as np import cv2 def convert_json_to_mask(json_path, img_path, out_path, label2idx): with open(json_path, encoding="utf-8") as f: data = json.load(f) img = cv2.imread(img_path) h, w = img.shape[:2] mask = np.zeros((h, w), dtype=np.uint8) for shape in data["shapes"]: label = shape["label"] if label not in label2idx: continue pts = np.array(shape["points"], dtype=np.int32) pts = pts.reshape((-1, 1, 2)) cv2.fillPoly(mask, [pts], color=label2idx[label]) cv2.imwrite(out_path, mask) label2idx = { "crack": 1, "spalling": 2, "water_seepage": 3, "efflorescence": 4, "hollow": 5 }

3.2 多边形顶点必须从float转int32,否则填充会错位

上面代码里np.array(shape["points"], dtype=np.int32)这一步是很多人容易漏的。labelme的顶点坐标是浮点数,cv2.fillPoly虽然能接受浮点数组,但在某些OpenCV版本下会出现填充区域偏移一到两个像素的“毛边”现象。尤其是裂缝这种细长形状,偏移两个像素可能直接把裂缝抹掉一半。所以我总是先转成np.int32再reshape成(-1, 1, 2),这是OpenCV绘制函数的标准输入格式。

3.3 边长不足3个像素的多边形要过滤掉

建筑损伤数据里,有些标注人员会对着一条极细裂缝点三下就存盘,生成的多边形面积只有几个像素。这类碎多边形在fillPoly填充后基本等于噪点,还会让损失函数在边界处产生大量震荡。我的处理方式是在转换时顺手计算多边形面积,面积小于10像素的直接丢弃:

area = cv2.contourArea(pts) if area < 10: continue

判定面积用cv2.contourArea,它对逆时针或顺时针顶点都能算出绝对值。面积阈值可以按图片分辨率动态调整,如果是1920×1080的图,阈值提到50也不为过。这是一步很值得做的预处理,能让掩码质量肉眼可见地提高。

3.4 掩码与原始图像尺寸不一致的两种场景

一种场景是JSON里的imageWidth和imageHeight字段与读取的实际图像尺寸不一致,这通常发生在标注过程中有人对图片做过旋转或缩放后忘了同步。另一种场景是批量处理时JSON文件名与图片文件名不匹配,导致拿A图的JSON去B图上画掩码,坐标全部错位。

我的做法是转换脚本里不信任JSON里的宽高字段,一律用cv2.imread实际读取图像尺寸。文件名匹配则通过imagePath字段解析后再拼一次路径,同时做一次存在性检查:

img_name = os.path.basename(data["imagePath"]) img_path = os.path.join(image_dir, img_name) if not os.path.exists(img_path): print(f"图片缺失:{img_path}") continue

如果图像尺寸在标注后被人为缩放过,先跑一个批处理把原图和JSON配对重命名,再做转换。这比其他任何方式都省时间。

4. 20类墙壁损伤的训练接入:数据划分、样本均衡与增强策略

4.1 按图片级划分,别按多边形级划分

分割任务的数据划分和分类任务有一个显著区别:同一张图上的多个缺陷是高度相关的,它们共享同样的光照、墙面材质和拍摄距离。如果划分时把同一张图的多边形拆到训练集和验证集,验证分数会虚高,因为模型其实见过了同一纹理背景的局部。所以划分必须按图片级别来,整张图片连同它的所有掩码一起归入某个集合。

7820张这个规模下有另一个问题:20个类别里可能存在“一个类别只出现在几百张图里”的长尾情况。简单随机划分会让某些小类在验证集中完全消失,或者在训练集中数量不足。我一般先按类别分桶,再在每个桶内按比例抽样,保证各集合的类别分布接近:

import random import glob import shutil random.seed(42) train_ratio, val_ratio = 0.8, 0.1 # 剩余0.1作测试 paths = glob.glob("labels/*.json") label_images = {} for p in paths: with open(p, encoding="utf-8") as f: data = json.load(f) labels = set([s["label"] for s in data["shapes"]]) primary = sorted(labels)[0] label_images.setdefault(primary, []).append(p) train, val, test = [], [], [] for label, items in label_images.items(): random.shuffle(items) n_train = int(len(items) * train_ratio) n_val = int(len(items) * val_ratio) train += items[:n_train] val += items[n_train:n_train + n_val] test += items[n_train + n_val:]

这段代码的分桶策略是:每张图以第一个标签作为主类别分入桶,再在桶内做随机抽样。它不能完美保证类别分布,但能大幅降低长尾类在验证集中缺失的风险。想更精确时可以用分层抽样库或写约束优化的划分逻辑,但对7820张的数据集来说,分桶抽样已经足够稳定,执着于精确分层性价比不高。

4.2 20类的类别权重怎么算才不翻车

类别不平衡是建筑损伤数据绕不开的问题。如果裂缝类占了40%的多边形,而“补丁修复痕迹”只占0.5%,直接训练会出现严重偏向多数类的现象。业界标准做法是给loss加类别权重,反向传播时让少数类的错分付出更大代价。

计算类别权重最常见的方案是median frequency balancing,即对每个类别的像素频次取中位数,然后让每个类的权重等于中位数除以该类的频次。这个方案能防止超大类别把权重压到非常小的情况。直接在训练脚本里实现:

import numpy as np # 统计所有掩码图中各类别像素数 class_counts = np.zeros(num_classes) for mask_path in train_masks: mask = cv2.imread(mask_path, cv2.IMREAD_GRAYSCALE) for c in range(1, num_classes): class_counts[c] += np.sum(mask == c) # 类别像素占比可能很小,用浮点数计算 freq = class_counts / class_counts.sum() median_freq = np.median(freq[freq > 0]) weights = np.array([median_freq / f if f > 0 else 0 for f in freq])

注意背景类(索引0)通常直接设成0或极小值,不让背景主导梯度。权重数组最后还要转成torch.from_numpy(weights).float()传给nn.CrossEntropyLoss(weight=...)。这套逻辑本身不难,难的是对长尾类别的涨幅控制。如果某个类别只有几十个样本,权重会飙到背景的几十倍,训练时该类别一旦误判会导致loss剧烈震荡。我通常会把权重做一次clip,限制最大不超过10:

weights = np.clip(weights, 0.0, 10.0)

4.3 墙壁损伤分割的增强策略:少用旋转,善用弹性形变

分割数据增强有两个与分类不同的约束:增强必须同时作用于图像和掩码,且几何变换不能破坏损伤边缘的语义。墙壁裂缝、剥落这类缺陷对旋转比较敏感,但也不是所有旋转都能用。带90度倍数的旋转不影响语义,45度这种任意角度旋转会让裂缝走向改变,墙面上竖向裂缝和斜向裂缝的形态特征是明显不同的。所以我的默认策略是:只做0、90、180、270度整倍数旋转,不做任意角度旋转。

水平翻转和垂直翻转是必开的,这能直接让样本量翻四倍。加上亮度对比度扰动和轻微高斯噪声,总共能撑起不小的有效样本量。对墙壁缺陷这种边缘极其重要的任务,elastic deformation(弹性形变)往往比random crop更有价值,因为它能模拟墙体表面因温度应力产生的细微弯曲形变。

import albumentations as A train_transform = A.Compose([ A.RandomRotate90(p=0.5), A.HorizontalFlip(p=0.5), A.VerticalFlip(p=0.2), A.RandomBrightnessContrast(brightness_limit=0.15, contrast_limit=0.1, p=0.6), A.GaussNoise(var_limit=(5.0, 20.0), p=0.3), A.OneOf([ A.ElasticTransform(alpha=1, sigma=50, alpha_affine=30, p=0.3), A.GridDistortion(distort_limit=0.2, p=0.3), ], p=0.4), ], additional_targets={"mask": "mask"})

注意additional_targets这个参数,它是albumentations配合分割任务的固定写法,让相同的随机变换同时作用到图像和掩码上。用这个库时有个版本坑:旧版本用ElasticTransform需要单独传mask参数,新版本已经统一到additional_targets机制。如果升级了库版本后代码报意外错误,先查这里。

4.4 训练时怎么用mask去统计每类的出现频率

分割训练里还有一个比加权loss更细腻的操作:按图统计类别出现次数,控制采样的batch构成。这是为了让“一张图里只有背景和一条裂缝”的简单样本,与“一张图里同时有裂缝、渗水、剥落”的复杂样本在同一个batch中出现。最简单有效的方式是做ClassBalancedSampler,每张图根据它包含的类别计算采样权重,权重与类别稀有度成正比。

实现上不必过度设计,我通常只在数据加载器里给每张训练图预计算一个三元组特征:包含哪些类别、各类别像素占比、是否是长尾类别。然后每次采样时随机挑一个目标类别,再根据目标类别筛出包含该类的图片子集,在子集内随机抽一张。这个逻辑其实30行代码就能写完,效果比全局随机采样稳定得多。

5. labelme工具链避坑:安装、版本冲突与标注质量检查

5.1 labelme安装总卡在PyQt5上,换清华镜像也只能部分解决

热词里频繁出现“labelme无法安装pyqt5”和“labelme error pyqt5-sip”,这不是个别现象,是labelme在Python 3.9以上版本安装时的经典问题。labelme依赖PyQt5,而PyQt5又依赖PyQt5-sip。新版本sip的API与老版本PyQt5存在兼容裂缝,pip在解析依赖时可能把sip升到不兼容的版本,导致启动labelme直接报AttributeError或ImportError。

常见做法是先用清华镜像源安装PyQt5,再单独钉死sip版本,最后装labelme:

pip install PyQt5==5.15.9 -i https://pypi.tuna.tsinghua.edu.cn/simple pip install PyQt5-sip==12.12.1 -i https://pypi.tuna.tsinghua.edu.cn/simple pip install labelme==5.8.3 -i https://pypi.tuna.tsinghua.edu.cn/simple

这三步的关键在于:先装PyQt5和sip,并且版本配对,5.15.9对应12.12.1是经过大量用户验证的组合。之后装labelme,pip不会再自己拉新的sip。如果已经装乱了,先卸载干净再按顺序装:

pip uninstall labelme PyQt5 PyQt5-sip PyQt5-Qt5 -y

5.2 标注文件缺图、空标注和重复标注的批量体检

7820张数据的标注质量不可能全靠人工检查,需要自动体检。我做数据质检时通常会跑一个扫描脚本,输出三类问题:JSON引用的图片文件不存在、shapes数组为空、同一图片存在重复的类同多边形。

import json, os problems = [] for name in os.listdir("labels"): if not name.endswith(".json"): continue with open(os.path.join("labels", name), encoding="utf-8") as f: data = json.load(f) img_path = os.path.join("images", os.path.basename(data["imagePath"])) if not os.path.exists(img_path): problems.append((name, "missing_image")) if len(data["shapes"]) == 0: problems.append((name, "empty_shapes")) labels = [s["label"] for s in data["shapes"]] if len(labels) != len(set(labels)): problems.append((name, "duplicate_label")) for p in problems: print(p)

重复标注的判定在这一步比较粗:一张图内两个多边形都叫“crack”并不一定是错误,比如两面墙各有独立裂缝时反而应该分开标注。但“同一区域被两个标注人员重复画了两遍”这种问题在多人协作时经常出现,肉眼看不出,需要转成掩码后做逐像素重叠检测。我会在后处理阶段把所有类别掩码叠加统计,发现同一像素被多个类别填充时,优先保留面积更大的那个标注,并记下冲突位置人工复核。

5.3 中文标签在Windows和Linux之间的编码折腾

这套数据集如果标注时用的是中文版labelme,JSON文件内的label字段是中文,文件编码大概率是UTF-8或GBK。Windows下用记事本保存偶发BOM头,导致Linux下读JSON时第一个键名变成\ufeffversion。遇到这种情况,Python的json.load会直接报错。加一行utf-8-sig编码读取即可兼容:

import json with open(json_path, encoding="utf-8-sig") as f: data = json.load(f)

utf-8-sig可以同时兼容带不带BOM的文件。如果你已经统一把所有标签映射成英文了,建议顺手用该编码把JSON重写一遍,彻底消除隐患。

5.4 标注工具版本与数据文件版本不匹配

这个坑比较隐蔽。labelme在3.x和5.x版本之间改过JSON结构,旧版本标注文件里的line_color、fill_color字段被移除,同时在shapes里增加了is_shape标志。如果团队里有人用老版本标注软件继续标注,混入旧结构文件会导致新版本脚本解析时读取到不存在的键。

统一做法是:拿到数据集后先做一次版本归一化。以5.8.3版本的结构为准,把旧版本字段删掉或补上。写一个小的清理脚本,遍历JSON,检查每个shape是否缺少shape_type或flags字段,缺失就补默认值。

for shape in data["shapes"]: shape.setdefault("shape_type", "polygon") shape.setdefault("flags", {}) shape.setdefault("group_id", None)

5.5 没有做掩码可视化就敢直接训练,是最贵的翻车

很多同学做完转换就急着开训练,结果第一轮loss降到不错的数值,推理出来却是一团浆糊。原因是掩码转换后没有做人工可视化检查。labelme的JSON在GUI里看是正常的,但转成掩码之后,细裂缝可能因为坐标偏移断了、小面积多边形可能被过滤掉、不同类别的重叠区域可能被后画的覆盖。我要求自己每做一次转换,就随机抽50张图,把原图、掩码、半透明叠加图拼成一张大面板整体过目:

import cv2 import numpy as np img = cv2.imread("sample.jpg") mask = cv2.imread("sample_mask.png", cv2.IMREAD_GRAYSCALE) color_mask = cv2.applyColorMap((mask * 40).astype(np.uint8), cv2.COLORMAP_TURBO) overlay = cv2.addWeighted(img, 0.6, color_mask, 0.4, 0) combined = np.hstack([img, overlay]) cv2.imwrite("check_overlay.png", combined)

叠加图一眼就能看出掩码是不是贴合了真实缺陷边缘。这一步虽然俗气,但它是所有后续训练、验证、调参的前提。没有经过可视化的掩码,即使统计指标再漂亮,也只是自欺欺人。

6. 评估模型不能只看mIoU:选指标、做混淆矩阵、优化边界预测

6.1 建筑损伤场景为什么mIoU不足为信

语义分割的标准评估指标是mIoU,但这里有个行业内的经验问题:裂缝、剥落这类缺陷的像素占比极低,多数图片的缺陷像素比例不足5%。在这种极端不平衡下,mIoU会被背景类的大面积正确预测稀释,模型即使完全没有分割出任何裂缝,mIoU也可能高达90%以上。所以真正要看的指标是每一类的IoU和recall,尤其是“裂缝”这类细长目标。

用Python做逐类评估时,我建议把每个类别的IoU都打印出来:

iou_per_class = {} for cls in range(1, num_classes): intersection = np.sum((pred == cls) & (gt == cls)) union = np.sum((pred == cls) | (gt == cls)) iou = intersection / (union + 1e-6) iou_per_class[cls_name[cls]] = round(iou, 4)

当某两类(比如“渗水”和“泛碱”)的IoU都很低时,别急着调模型,先看一眼混淆矩阵。这两种缺陷在颜色和纹理上高度相似,标注人员自己都可能画混,模型分不清是正常的。这时更实际的做法不是调loss,而是合并语义相近的类别,或者让后处理规则根据位置和面积做二次判定。

6.2 细长裂缝的召回率为什么普遍偏低

裂缝是所有类别里最棘手的,它细、长、断续、和墙面阴影边界难以区分。分析这类目标的失败案例时,我已经不满足于只看掩码了,更常用的手段是把预测mask叠加到原图上,然后找预测和GT不一致的区域,逐个看是漏检还是边界错位。细裂缝漏检的主因通常是特征图下采样倍数过大,一个裂缝宽度只有3像素,经过两次stride=2的卷积后只剩不到1像素的响应。这时能用两个手段补救:输出特征图保持stride=8或更小的下采样倍数,或者在训练时对裂缝类像素凸出采样。

具体到代码,最直接的参数是loss里的ignore_index和采样权重。把背景像素的权重压到0.2,把裂缝类权重提到5以上,训练时让背景不再主导梯度方向,漏检现象会明显改善。这个手段要配合早停使用,不然训练后期会过拟合到裂缝训练样本的特定纹理上。

6.3 分割结果转回labelme格式做人工复核

模型训练完,总会面临一个交付问题:建筑领域的使用者不认PNG掩码,他们要的是能在labelme里打开的标注文件。把预测掩码转成labelme JSON格式并不难,核心思路是提取每个类别的连通域,用cv2.findContours拿到边界点,再写成JSON结构。

import cv2 import json mask = cv2.imread("pred_mask.png", cv2.IMREAD_GRAYSCALE) shapes = [] for cls in range(1, num_classes): binary = (mask == cls).astype(np.uint8) contours, _ = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) for cnt in contours: if len(cnt) < 3: continue points = cnt.reshape(-1, 2).tolist() shapes.append({"label": class_names[cls], "points": points, "group_id": None, "shape_type": "polygon", "flags": {}}) out = {"version": "5.8.3", "flags": {}, "shapes": shapes, "imagePath": "image.jpg", "imageData": None} with open("pred.json", "w", encoding="utf-8") as f: json.dump(out, f, ensure_ascii=False)

这一步是项目交付的最后一个关口。只有让建筑工程师能在labelme里打开预测结果,手动微调多边形顶点后直接入库,整个数据管线才算真正闭环。我在多个项目里吃过亏才发现这个问题——模型表现再好,如果结果不能回流到现有标注工具链里,就是白干。这也是“labelme格式”这个后缀对整个数据集的真正价值。

做这套流程到现在,最大的教训是:拿到一份标注数据集,最先做的永远是探明它内部的一致性——标签命名、尺寸信息、编码格式、多边形质量,而不是追求最强模型。这些基础工作琐碎不起眼,但每一项都能在训练时省下数倍的返工时间。7820张20类别的数据量不算小,如果数据质量工作做到位,完全能训练出一个在真实墙面上具备实用价值的缺陷分割模型;如果跳过前面几步,再先进的网络结构也是白搭。希望这次的拆解能让你少走一段弯路,帮到你。

本文还有配套的精品资源,点击获取

返回列表