尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

基于U-Net与Python的矿区无人机影像语义分割实战指南

基于U-Net与Python的矿区无人机影像语义分割实战指南 简介语义分割是计算机视觉中的一项核心技术旨在为图像中的每个像素分配一个类别标签从而实现像素级的场景理解。其核心原理是通过深度神经网络学习图像特征并逐像素进行分类。这项技术在遥感影像分析、自动驾驶、医疗影像诊断等领域具有极高的技术价值。在遥感领域特别是针对无人机影像的地物识别与提取语义分割能够高效、自动化地完成土地覆盖分类、变化检测等任务极大地提升了传统人工解译的效率。本文聚焦于矿区这一特定应用场景详细阐述了如何利用U-Net模型架构与Python技术栈构建一套完整的无人机影像语义分割解决方案以应对矿区地物提取中面临的尺度变化、类别不平衡等挑战。1. 项目概述当无人机飞过矿区我们如何让AI看懂地面如果你手头有一堆从矿区飞回来的无人机照片看着上面密密麻麻的矿坑、道路、堆积的矿渣、稀疏的植被还有那些大型机械是不是有点头疼靠人眼一张张去圈、去标注效率低不说还容易出错。这个项目要解决的就是这么一个非常实际的问题如何用Python和语义分割技术让计算机自动从无人机影像里把不同的地物比如裸露地表、植被、水体、建筑物、道路给“抠”出来。这听起来像是学术界的前沿课题但其实在矿山监测、环境评估、土地复垦规划这些一线场景里需求非常迫切。管理者需要知道矿区的开采范围变化、植被恢复情况、水土流失区域传统方法费时费力。而“语义分割”这项技术简单说就是给图像里的每一个像素都打上标签告诉你这个像素点属于“道路”还是“植被”最终得到一张彩色的、分类明确的结果图。我这次分享的就是一套完整的实验源码和心得。它不仅仅是一堆代码更是一个从数据准备、模型训练到结果分析的全流程实战记录。你会发现把最新的AI模型比如U-Net、DeepLabV3用在无人机影像上会遇到不少在自然场景图片里遇不到的麻烦尺度变化大、地物边界模糊、同类地物光谱差异显著等等。下面我就把这套“让AI看懂矿区”的方法掰开了揉碎了讲给你听。2. 核心思路与技术选型为什么是语义分割为什么用这个模型拿到“矿区无人机影像地物提取”这个任务首先得明确技术路线。目标检测框出物体和实例分割区分不同个体在这里都不太合适因为我们需要的是对整片区域进行连续的分类尤其是对背景如裸露岩土的提取。因此像素级的语义分割是唯一正确的起点。2.1 模型架构的抉择U-Net 还是 DeepLabV3在语义分割领域U-Net和DeepLabV3是两座绕不开的丰碑。针对无人机影像的特点我们需要仔细权衡。U-Net以其经典的编码器-解码器结构和跳跃连接闻名。它的优势在于结构清晰、参数量相对较小、训练速度快并且在数据量不是特别巨大的情况下也能凭借跳跃连接保留较多的空间细节信息。这对于无人机影像中那些细长的道路、沟渠或者小块的植被斑块来说是至关重要的。DeepLabV3则引入了“空洞卷积”和“空间金字塔池化”模块它的强项在于捕捉多尺度上下文信息。矿区影像的一个典型特点是地物尺度差异巨大近处的卡车可能只占几十个像素而远处的排土场可能绵延上千像素。DeepLabV3的多尺度感知能力理论上能更好地处理这种变化。我的选择与理由在这个项目中我最终以U-Net作为基线模型进行深度开发。原因有三第一无人机影像分辨率通常很高如2048x2048DeepLabV3的复杂模块在训练时对显存要求更高不易调整。第二矿区地物虽然尺度多变但边界清晰度往往比自然场景如街景更重要U-Net的跳跃连接在边缘保持上更直观可控。第三U-Net的社区生态极其丰富各种改进变体如Attention U-Net, ResUNet可以方便地集成为我们后续优化提供了灵活的基础。当然这并不代表DeepLabV3不好在后续的对比实验中我也会将其作为一个重要的对比基线。2.2 骨干网络Backbone的搭配特征提取器的选择模型确定了骨架还需要一个强大的“眼睛”来提取特征这就是骨干网络。我们通常使用在ImageNet上预训练好的分类网络作为编码器。VGG16经典但略显笨重特征提取能力足够但参数量大。ResNet34/50引入了残差连接训练更稳定能构建更深的网络在保持细节和提取高级语义间取得了很好平衡是当前最主流的选择之一。EfficientNet通过复合缩放系数统一优化深度、宽度和分辨率在精度和效率上做到了极致是追求“轻量化”和“高性能”的首选。我的实操心得对于矿区这种特征相对鲜明、但数据量可能有限的场景ResNet34是一个非常好的起点。它在提供足够强的特征提取能力的同时不至于像ResNet50那样“杀鸡用牛刀”训练和推理速度都更有优势。我在项目初期使用ResNet34作为U-Net的编码器快速实现了基线模型验证了流程的可行性。后期为了提升精度可以无缝切换到ResNet50或EfficientNet-B4。2.3 数据集的挑战与对策“巧妇难为无米之炊”数据集是模型成败的关键。公开的无人机数据集如Aeroscapes多针对城市或一般场景专门针对矿区的非常稀少。这意味着我们很可能需要自建数据集。数据获取使用大疆等行业级无人机进行正射摄影获取高分辨率、多光谱至少包含RGB影像。飞行规划要保证足够的重叠度以便后期拼接。数据标注这是最耗时的一步。使用LabelMe、CVAT等工具进行像素级标注。地物类别需要预先定义清楚例如Class 0: 背景/未标注区域Class 1: 裸露地表包括岩石、土壤、矿渣Class 2: 植被Class 3: 水体矿坑积水、沉淀池Class 4: 建筑物工棚、厂房Class 5: 道路Class 6: 大型设备可选数据格式原始影像保存为JPG或PNG。标注文件通常保存为单通道的PNG图像其中每个像素的灰度值对应其类别ID如012...。同时需要生成一个class_dict.csv文件明确ID与类别名称、显示颜色的对应关系。3. 环境搭建与核心代码解析理论说得再多不如一行代码。这里我带你走通整个项目的核心环节。3.1 环境配置一步到位我强烈建议使用Conda管理环境避免包版本冲突。以下是完整的environment.yaml文件name: mine_seg channels: - pytorch - conda-forge - defaults dependencies: - python3.8 - pytorch1.12.1 - torchvision0.13.1 - cudatoolkit11.3 # 根据你的CUDA版本调整 - pip - pip: - opencv-python4.8.1 - pillow10.0.0 - numpy1.24.3 - pandas2.0.3 - matplotlib3.7.2 - scikit-learn1.3.0 - tqdm4.65.0 - segmentation-models-pytorch0.3.3 # 一个极好的语义分割模型库 - albumentations1.3.1 # 强大的数据增强库 - tensorboard2.13.0 # 可选用于可视化训练过程在终端执行conda env create -f environment.yaml然后conda activate mine_seg基础环境就准备好了。segmentation-models-pytorch(SMP) 这个库封装了U-Net、DeepLabV3等众多模型及其预训练骨干能让我们省去大量搭建模型的重复劳动。3.2 数据加载与增强策略无人机影像数据增强至关重要因为实际数据有限且需要让模型对光照、角度、尺度变化具有鲁棒性。import albumentations as A from albumentations.pytorch import ToTensorV2 def get_train_transform(): return A.Compose([ A.RandomResizedCrop(height512, width512, scale(0.8, 1.2)), # 随机裁剪和缩放 A.HorizontalFlip(p0.5), # 水平翻转 A.VerticalFlip(p0.5), # 垂直翻转 A.RandomRotate90(p0.5), # 90度旋转 A.OneOf([ # 随机选择一种颜色扰动 A.RandomBrightnessContrast(brightness_limit0.2, contrast_limit0.2, p1), A.HueSaturationValue(hue_shift_limit20, sat_shift_limit30, val_shift_limit20, p1), A.RGBShift(r_shift_limit20, g_shift_limit20, b_shift_limit20, p1), ], p0.8), A.CLAHE(clip_limit2.0, tile_grid_size(8,8), p0.3), # 自适应直方图均衡增强对比度 A.GaussNoise(var_limit(10.0, 50.0), p0.3), # 高斯噪声模拟成像噪声 A.Normalize(mean[0.485, 0.456, 0.406], std[0.229, 0.224, 0.225]), # ImageNet统计量归一化 ToTensorV2(), ]) def get_val_transform(): # 验证集只需要最基础的预处理不能做随机增强 return A.Compose([ A.Resize(height512, width512), A.Normalize(mean[0.485, 0.456, 0.406], std[0.229, 0.224, 0.225]), ToTensorV2(), ])注意事项Albumentations库在处理图像和掩膜mask的同步变换上非常方便且准确远超一些自定义的增强函数。对于矿区影像我特别加入了CLAHE和GaussNoise因为无人机在不同光照条件下拍摄影像的对比度和噪声水平差异很大这些增强能显著提升模型的泛化能力。3.3 模型定义与损失函数选择使用SMP库定义模型只需一行代码。但损失函数的选择是语义分割的精髓。import torch import segmentation_models_pytorch as smp # 定义模型 model smp.Unet( encoder_nameresnet34, # 骨干网络 encoder_weightsimagenet, # 使用ImageNet预训练权重 in_channels3, # 输入通道数 (RGB) classes6, # 输出类别数含背景 activationNone, # 输出不激活后面接Softmax或Sigmoid ) # 将模型移至GPU device torch.device(cuda if torch.cuda.is_available() else cpu) model model.to(device) # 定义组合损失函数 import torch.nn as nn class DiceBCELoss(nn.Module): def __init__(self, weightNone, size_averageTrue): super(DiceBCELoss, self).__init__() self.bce_loss nn.BCEWithLogitsLoss(weightweight) def forward(self, inputs, targets, smooth1): # inputs: 模型原始输出 [B, C, H, W] # targets: one-hot编码的标签 [B, C, H, W] # 对每个类别计算Dice Loss inputs torch.sigmoid(inputs) # 如果activationNone需要先sigmoid # 展平 inputs inputs.view(-1) targets targets.view(-1) intersection (inputs * targets).sum() dice_loss 1 - (2.*intersection smooth)/(inputs.sum() targets.sum() smooth) BCE self.bce_loss(inputs, targets) Dice_BCE BCE dice_loss # 结合两种损失 return Dice_BCE # 对于多类别更常用的是CrossEntropyLoss DiceLoss # SMP提供了现成的多类别Dice Loss criterion smp.losses.DiceLoss(modemulticlass) # 或者组合损失 criterion nn.CrossEntropyLoss(weightclass_weights) # class_weights用于处理类别不平衡 # 优化器 optimizer torch.optim.Adam(model.parameters(), lr1e-4)核心解析为什么用Dice Loss或它的组合在语义分割中我们关心的往往是目标区域如植被、水体的“重叠度”。交叉熵损失CE平等对待每一个像素但当前景我们关心的地物和背景如大片的裸露地表像素数量严重不平衡时模型会倾向于预测背景来降低损失。Dice系数直接衡量预测区域和真实区域的交集大小对类别不平衡不敏感。因此“CE Dice”的组合在实践中被证明非常有效。SMP库封装好了这些损失直接调用即可。3.4 训练循环中的关键技巧训练循环是核心这里有几个提升性能的细节。from torch.utils.data import DataLoader from tqdm import tqdm def train_one_epoch(model, dataloader, optimizer, criterion, device, schedulerNone): model.train() running_loss 0.0 pbar tqdm(dataloader, descTraining) for images, masks in pbar: images images.to(device) masks masks.to(device).long() # 标签是类别索引需要是Long类型 # 前向传播 outputs model(images) # [B, C, H, W] # 计算损失 loss criterion(outputs, masks) # 反向传播与优化 optimizer.zero_grad() loss.backward() optimizer.step() running_loss loss.item() pbar.set_postfix({loss: f{loss.item():.4f}}) epoch_loss running_loss / len(dataloader) if scheduler: scheduler.step() # 调整学习率 return epoch_loss # 验证函数 def validate(model, dataloader, criterion, device): model.eval() val_loss 0.0 with torch.no_grad(): for images, masks in tqdm(dataloader, descValidating): images, masks images.to(device), masks.to(device).long() outputs model(images) loss criterion(outputs, masks) val_loss loss.item() return val_loss / len(dataloader)实操心得学习率调度一定要用。torch.optim.lr_scheduler.ReduceLROnPlateau是个好选择当验证损失不再下降时自动降低学习率。梯度累积如果显存不够无法设置较大的batch_size可以使用梯度累积。每N个小批次累加梯度后再更新一次权重相当于增大了有效批次大小。混合精度训练使用torch.cuda.amp进行自动混合精度训练可以大幅减少显存占用加快训练速度且通常不会损失精度。早停监控验证集损失或指标如mIoU连续多个epoch没有提升就停止训练防止过拟合。4. 模型训练、评估与结果可视化模型训练起来后我们更需要关注它学得怎么样结果是否可用。4.1 评估指标不仅仅是准确率对于语义分割像素准确率Pixel Accuracy是个很差的指标因为背景像素占大多数即使全预测为背景准确率也会很高。我们必须看更细致的指标。交并比IoU对每个类别单独计算。IoU TP / (TP FP FN)。它衡量的是预测区域和真实区域的重合程度。平均交并比mIoU所有类别IoU的平均值。这是最核心的评估指标。频率加权交并比FWIoU根据每个类别的像素出现频率对IoU进行加权更能反映模型在常见类别上的表现。from sklearn.metrics import confusion_matrix, jaccard_score import numpy as np def calculate_iou(pred_mask, true_mask, num_classes): 计算每个类别的IoU和mIoU pred_mask, true_mask: [H, W] 值为类别索引 iou_list [] for cls in range(num_classes): pred_cls (pred_mask cls) true_cls (true_mask cls) if true_cls.sum() 0: # 真实中没有该类 if pred_cls.sum() 0: iou 1.0 # 两者都没有视为完美 else: iou 0.0 # 虚警 else: intersection np.logical_and(pred_cls, true_cls).sum() union np.logical_or(pred_cls, true_cls).sum() iou intersection / (union 1e-10) iou_list.append(iou) miou np.mean(iou_list) return miou, iou_list4.2 结果可视化一眼看出好坏训练过程中和训练后可视化是必不可少的调试和展示手段。import matplotlib.pyplot as plt def visualize_prediction(image, true_mask, pred_mask, class_names, save_pathNone): 可视化原始图像、真实标签和预测结果 image: [H, W, 3] numpy array, 值范围0-255 true_mask, pred_mask: [H, W] 类别索引 fig, axes plt.subplots(1, 3, figsize(15, 5)) # 原始图像 axes[0].imshow(image) axes[0].set_title(Original Image) axes[0].axis(off) # 真实标签彩色 cmap plt.cm.get_cmap(tab20, len(class_names)) # 使用离散色彩映射 true_rgb cmap(true_mask)[:, :, :3] # 取RGB通道 axes[1].imshow(true_rgb) axes[1].set_title(Ground Truth) axes[1].axis(off) # 预测结果彩色 pred_rgb cmap(pred_mask)[:, :, :3] axes[2].imshow(pred_rgb) axes[2].set_title(Prediction) axes[2].axis(off) # 添加图例 from matplotlib.patches import Patch legend_elements [Patch(facecolorcmap(i), labelname) for i, name in enumerate(class_names)] axes[2].legend(handleslegend_elements, bbox_to_anchor(1.05, 1), locupper left) plt.tight_layout() if save_path: plt.savefig(save_path, dpi300, bbox_inchestight) plt.show()避坑指南可视化时一定要将预测结果和真实标签放在完全相同的色彩映射下对比否则颜色对不上会误导判断。我常用matplotlib的tab20离散色板它能清晰区分10-20个类别。对于超过20类的任务需要自定义色彩映射或使用其他方法。5. 针对矿区场景的专项优化策略用通用模型跑通流程只是第一步。要让模型在矿区这个特定场景下表现出色必须进行针对性优化。5.1 处理极端类别不平衡矿区影像中“裸露地表”可能占据80%以上的像素而“道路”、“水体”等可能不到5%。直接训练会导致模型忽略小类别。解决方案损失函数加权在CrossEntropyLoss中为每个类别设置权重。权重通常与类别频率成反比。例如weight 1.0 / (class_frequency epsilon)。在线难例挖掘OHEM在损失计算时只针对那些预测错误难例的像素进行反向传播强迫模型关注它不擅长的部分。数据层面过采样在数据加载时对包含稀有类别的训练样本给予更高的采样概率。使用更适合的损失如前文提到的Dice Loss、Focal Loss对难分类样本给予更高权重等。# 计算类别权重示例 def calculate_class_weights(dataset): 遍历数据集统计每个类别的像素频率 pixel_counts np.zeros(num_classes) total_pixels 0 for _, mask in dataset: unique, counts np.unique(mask.numpy(), return_countsTrue) for cls, cnt in zip(unique, counts): pixel_counts[int(cls)] cnt total_pixels mask.numel() frequency pixel_counts / total_pixels weights 1.0 / (frequency 1e-6) # 加平滑项防止除零 weights weights / weights.sum() * num_classes # 归一化 return torch.tensor(weights, dtypetorch.float32) # 在损失函数中使用 class_weights calculate_class_weights(train_dataset) criterion nn.CrossEntropyLoss(weightclass_weights.to(device))5.2 多尺度训练与测试Test Time Augmentation, TTA无人机影像地物尺度多变。为了提升模型鲁棒性可以在训练和测试时引入多尺度。多尺度训练在数据增强阶段不仅进行随机裁剪还可以随机将图像缩放到不同尺度如0.75x, 1.0x, 1.25x再进行裁剪。这能迫使模型学习尺度不变的特征。测试时增强TTA对同一张测试图像生成多个不同尺度或经过轻微增强如水平翻转的版本分别输入模型得到预测然后将这些预测结果进行融合如取平均或投票得到最终结果。这几乎总能带来小幅度的精度提升但会成倍增加推理时间。# 简单的TTA实现水平翻转 def predict_with_tta(model, image, device): model.eval() with torch.no_grad(): # 原始图像预测 output1 model(image.unsqueeze(0).to(device)).squeeze().cpu() # 水平翻转后预测 image_flipped torch.flip(image, dims[2]) # 假设dim[C,H,W] W是宽度维度 output2 model(image_flipped.unsqueeze(0).to(device)).squeeze().cpu() output2 torch.flip(output2, dims[1]) # 将预测结果翻回来 # 融合平均 fused_output (output1 output2) / 2 pred_mask torch.argmax(fused_output, dim0) # 取概率最大的类别 return pred_mask.numpy()5.3 后处理优化消除“椒盐噪声”与平滑边界模型原始的预测结果往往存在一些孤立的错误像素点椒盐噪声和锯齿状的边界。通过简单的后处理可以极大改善视觉效果和实际应用价值。连通域分析使用scipy.ndimage或OpenCV的connectedComponentsWithStats函数找出所有连通区域。可以设定一个面积阈值将面积过小的区域可能是噪声合并到其周围的主要类别中。形态学操作开运算先腐蚀后膨胀可以消除小的白色噪声点孤立的错误预测。闭运算先膨胀后腐蚀可以填充小的黑色空洞缺失的预测。使用一个小的圆形或方形结构元素如3x3对每个类别的二值掩膜单独处理。条件随机场CRF这是一个更高级的后处理技术它同时考虑像素本身的类别概率模型输出和像素之间的空间关系颜色相似度、位置接近度进行全局优化能使边界更加平滑、符合视觉直觉。可以使用pydensecrf库来实现。import cv2 import numpy as np def postprocess_mask(mask, min_area_threshold50): 后处理去除小面积噪声 mask: [H, W] 整数类型的标签图 processed_mask mask.copy() num_classes np.max(mask) 1 for cls in range(1, num_classes): # 通常不从背景类开始处理 # 创建当前类别的二值图像 binary_cls (mask cls).astype(np.uint8) # 找连通域 num_labels, labels, stats, centroids cv2.connectedComponentsWithStats(binary_cls, connectivity8) for i in range(1, num_labels): # 跳过背景标签0 area stats[i, cv2.CC_STAT_AREA] if area min_area_threshold: # 找到这个小区域的位置 component_mask (labels i) # 获取该区域周围像素的类别使用膨胀 kernel np.ones((3,3), np.uint8) dilated cv2.dilate(component_mask.astype(np.uint8), kernel, iterations1) neighbor_mask dilated - component_mask neighbor_classes mask[neighbor_mask 0] if len(neighbor_classes) 0: # 将其归并为周围最多的类别 new_cls np.argmax(np.bincount(neighbor_classes)) processed_mask[component_mask] new_cls return processed_mask6. 项目部署与实用化思考模型训练评估完毕精度也达标了接下来是如何让它真正用起来。6.1 模型部署从PyTorch到ONNX为了便于在不同平台如服务器、边缘设备上部署通常需要将PyTorch模型转换为更通用的格式如ONNX。import torch.onnx # 定义一个示例输入尺寸 dummy_input torch.randn(1, 3, 512, 512).to(device) # 导出模型 torch.onnx.export(model, dummy_input, mine_unet.onnx, export_paramsTrue, opset_version12, # 建议使用较高版本 do_constant_foldingTrue, input_names[input], output_names[output], dynamic_axes{input: {0: batch_size}, # 支持动态批次 output: {0: batch_size}}) print(Model exported to mine_unet.onnx)导出后你可以使用ONNX Runtime进行高性能推理它支持CPU、GPU等多种硬件后端。6.2 处理大尺寸影像滑动窗口预测无人机正射影像动辄上万像素无法直接输入网络。必须采用滑动窗口Sliding Window的方式进行预测。def predict_large_image(model, large_img, window_size512, stride256, devicecuda): 使用滑动窗口预测大图 large_img: [H, W, 3] numpy array return: [H, W] 预测的类别索引图 h, w, _ large_img.shape final_mask np.zeros((h, w), dtypenp.uint8) count_map np.zeros((h, w), dtypenp.uint8) # 记录每个像素被预测的次数 # 预处理函数与验证集相同 transform get_val_transform() model.eval() with torch.no_grad(): for y in range(0, h, stride): for x in range(0, w, stride): # 提取窗口 y_end min(ywindow_size, h) x_end min(xwindow_size, w) window large_img[y:y_end, x:x_end, :] # 如果窗口小于设定尺寸进行填充 if window.shape[0] window_size or window.shape[1] window_size: pad_h window_size - window.shape[0] pad_w window_size - window.shape[1] window np.pad(window, ((0, pad_h), (0, pad_w), (0,0)), modereflect) # 预处理并预测 augmented transform(imagewindow) img_tensor augmented[image].unsqueeze(0).to(device) output model(img_tensor) pred torch.argmax(output, dim1).squeeze().cpu().numpy() # 如果填充过裁剪回原始窗口大小 if window.shape[0] (y_end - y): pred pred[:y_end-y, :x_end-x] # 将预测结果累加到最终掩膜上这里简单覆盖更优方案是加权融合 final_mask[y:y_end, x:x_end] pred count_map[y:y_end, x:x_end] 1 # 处理重叠区域简单平均实际可使用高斯加权等 # 对于语义分割重叠区域直接取最后一次预测值问题不大或者对概率进行平均后再取argmax return final_mask重要提醒滑动窗口预测时窗口之间需要有重叠stride window_size否则在窗口边界处会产生明显的接缝。重叠区域的处理策略会影响最终结果简单的覆盖可能导致边界不连续更精细的做法是对每个像素的所有窗口预测概率进行平均再取argmax。6.3 工程化建议构建一个简单的推理服务要让非技术人员也能使用可以封装一个简单的Web服务。这里以Flask为例from flask import Flask, request, jsonify, send_file import numpy as np import cv2 import io from PIL import Image app Flask(__name__) # 加载模型... (此处省略) app.route(/predict, methods[POST]) def predict(): if file not in request.files: return jsonify({error: No file uploaded}), 400 file request.files[file] img Image.open(io.BytesIO(file.read())).convert(RGB) img_np np.array(img) # 调用预测函数包含滑动窗口等预处理 predicted_mask predict_large_image(model, img_np) # 将掩膜转换为彩色结果图 color_map [...] # 你的颜色映射 colored_result color_map[predicted_mask] # 保存结果到内存 result_img Image.fromarray(colored_result.astype(np.uint8)) img_byte_arr io.BytesIO() result_img.save(img_byte_arr, formatPNG) img_byte_arr.seek(0) return send_file(img_byte_arr, mimetypeimage/png) if __name__ __main__: app.run(host0.0.0.0, port5000, debugFalse)这样用户只需要通过网页或API上传无人机照片就能直接下载分割后的结果图。从无人机原始影像到最终的分割结果图这条路我走过不少弯路。最大的体会是在矿区这个特定场景下数据质量决定上限模型调优决定下限而后处理则决定了成果的“美观”与“可用”程度。不要一味追求最复杂的模型先把数据清洗、标注规范做好用一个稳健的基线模型如U-NetResNet34跑通全流程再针对性地解决类别不平衡、边界模糊等具体问题往往能取得事半功倍的效果。这套代码和文档就是一个坚实的起点你可以基于它去探索更复杂的模型、尝试多时相分析、甚至结合高程数据DSM进行三维地物提取让AI更好地为矿山智能化管理服务。本文还有配套的精品资源点击获取
返回列表