资讯动态

遥感目标检测项目实战:从环境配置到大图切片推理的完整指南

发布时间:2026/10/2 14:26:42 来源:尧图企业网站定制
简介基于Python的遥感图像目标检测完整项目包面向毕业设计、课程设计及遥感图像处理方向的开发者可解决从数据准备到模型训练与推理的落地问题。项目基于FAIR1M2.0遥感监测数据集涵盖环境安装、训练集与验证集合并、按分辨率灰度化等完整数据预处理流程目录结构按color与gray分支组织便于复现。资源共404个文件以350个Python源码文件为主体辅以22个YAML配置、22个Markdown说明、CSV结果文件与Jupyter Notebook分析脚本压缩包仅7.54MB轻量但功能完整。已有729人学习下载。从内容预览看还包含项目说明、配置文件、数据分析和测试Notebook等读者可参照说明快速完成环境配置、数据组织与检测实验既适合作为课设作业、毕设演示也可作为遥感目标检测入门进阶的参考范例。1. 从压缩包到可用模型遥感目标检测项目到底给你准备了什么拿到手是一个“基于python实现遥感图像物体目标检测源码模型项目说明.zip”常见的第一反应是解压、找 train.py、装依赖、直接开跑。但做过遥感目标检测的人都知道这个领域跟自然图像检测有个本质差别一张遥感影像可能是 5000×5000 甚至更大目标可能是几像素的汽车也可能是几百像素的厂房直接用自然图像的流程跑往往第一步就翻车。这个 zip 里真正值钱的不是那几段模型代码而是“怎么把尺寸巨大、目标稀疏、背景复杂的高分影像变成模型能吃的样本”这一整套处理逻辑。这个项目定位很明确给你一套从遥感影像到目标检测结果的完整链路包括基于 Python 的推理与训练源码、已经训练好的模型权重文件以及一份说明文档告诉你数据从哪来、标注格式怎么转、参数怎么调。如果你手头有遥感影像想做车辆、船只、飞机或建筑检测又不想从零开始攒代码这个包可以帮你把“跑通第一个检测结果”的周期从两周压缩到半天。适合三类人刚入门深度学习但熟悉 GIS 的从业者、需要在项目中快速验证遥感检测效果的工程师、以及想拿公开数据集做实验的学生。但要注意源码能跑通只是起点。遥感图像的检测效果受数据分布影响极大同一个模型在武汉的影像上训练拿去识别北欧的城区可能就失效。所以这篇文章不打算只解释代码怎么跑而是把整个项目的结构拆开告诉你每个模块解决什么问题、哪些参数必须调、哪些坑我踩过之后希望你绕开。2. 解压之后先别急着跑目录结构、依赖锁定与遥感数据格式2.1 目录结构里藏着项目的地图先看懂再动手解压后你会看到一个典型的深度学习工程布局核心无非是这几块数据目录、配置目录、源码目录、模型权重目录以及一份项目说明文档。这里给你一个我在多个遥感检测项目里验证过的标准目录参考无论你手里的包是不是严格长这样都能按这个思路去对照remote_sensing_detection/ ├── data/ # 数据目录原始影像、标注文件、划分好的训练/验证集 │ ├── images/ # 遥感影像通常是 TIF 或 JPG │ ├── labels/ # 标注文件常见是 YOLO 格式的 txt 或 VOC 格式的 xml │ └── dataset.yaml # 数据集配置文件声明类别数和类别名 ├── models/ # 模型权重目录 │ ├── best.pt # 训练好的权重用于推理或继续训练 │ └── last.pt # 最后一轮权重用于断点恢复 ├── src/ # 源码目录 │ ├── train.py # 训练入口 │ ├── detect.py # 推理入口 │ ├── utils/ # 工具函数图片切片、坐标转换、可视化 │ └── config.py # 全局配置学习率、batch size、输入尺寸 ├── project_notes.pdf # 项目说明文档 └── requirements.txt # Python 依赖列表拿到任何项目包第一步永远是读 requirements.txt 和项目说明而不是找 train.py。说明文档里通常会写着数据集来源、标注格式、类别数量、训练时用的硬件环境这些信息直接决定了你后面的参数设置。比如文档里写“模型输入 640×640类别为 car、ship、plane”那你的 dataset.yaml 类别顺序就必须严格一致否则加载权重后推理结果会张冠李戴。一个容易被忽略的细节遥感影像往往是 TIF 格式带多波段可能是 RGB 也可能是四波段甚至八波段。源码里如果只写了cv2.imread()遇到多波段 TIF 会直接报错或只读入第一个波段。检查项目里有没有专门的影像读取工具函数如果没有你需要自己补上 GDAL 或 rasterio 的读取逻辑。这不是小事我见过不少人在这一步卡住以为是环境问题其实是数据读取的问题。2.2 环境搭建的确定性Python 版本和依赖锁定是第一个坑遥感检测项目最常见的依赖冲突来自三个库OpenCV、GDAL 和 PyTorch。OpenCV 的版本会影响图像读取和预处理结果GDAL 用于读写地理参考信息但编译安装容易出问题PyTorch 的版本则直接关系到 GPU 驱动和 CUDA 版本。如果 requirements.txt 里只是列了包名没锁版本大概率你装出来的环境和作者的不一致。我一般建议用 conda 建一个干净的 Python 3.9 环境然后逐项安装依赖。先装 PyTorch再装其他包最后处理 GDAL。不要一上来就pip install -r requirements.txt那样 pytorch 会默认装 CPU 版本后面训练慢到怀疑人生。bash conda create -n rs_det python3.9 -y conda activate rs_det先按你的 CUDA 版本装 PyTorchCUDA 11.8 就用这条CUDA 12.1 换相应版本号pip install torch2.1.0 torchvision0.16.0 --index-url https://download.pytorch.org/whl/cu118再装项目依赖cd remote_sensing_detection pip install -r requirements.txt如果 requirements 里有 gdal或者你看项目说明发现要读 TIF单独装conda install gdal3.6.2验证环境python -c import torch, cv2; print(torch.version, torch.cuda.is_available(), cv2.version)这里的顺序是有讲究的先装 PyTorch 是为了保证拿到的是 CUDA 版本而不是 CPU 版本后面 pip 安装其他依赖时不会因为依赖冲突把 torch 降级或覆盖GDAL 用 conda 装而不是 pip是因为 pip 的 GDAL 需要自己编译经常在 Windows 上失败conda 有预编译好的二进制包。torch.cuda.is_available() 输出 True 是最低要求输出 False 说明你去检查一下驱动和 CUDA否则后面训练根本跑不起来。 验证环境时同时打印 OpenCV 版本不是多此一举。OpenCV 4.5 以上和 4.8 以上在处理某些图像插值算法上行为有差异特别是 cv2.resize 的默认插值方式影响的是训练时图像缩放的像素分布微小的差异累积起来会反映在最终精度上。如果条件允许尽量用项目作者锁定的版本不要用最新版。 ### 2.3 遥感数据格式与自然图像的本质区别TIF、波段和坐标系 说句实话遥感目标检测项目里最容易出问题的不是模型而是数据。自然图像目标检测的数据集比如 COCO一张图 512×512目标占画面比例大类别清晰。遥感影像完全不是这个玩法一张图可能是一个城市的 0.3 米分辨率影像面积几十平方公里目标密集区域和空白区域的比例可能达到 1:1000。 这意味着你需要关注三件事。第一是影像格式TIF 可能是压缩的也可能是未压缩的可能带地理坐标也可能不带读进来的数组维度可能是 (H, W, C) 也可能是 (C, H, W)。第二是目标尺度遥感影像里的目标像素大小和拍摄高度直接相关同样是车0.3 米分辨率下是 30×15 像素1 米分辨率下就只有 10×5 像素。第三是背景复杂度建筑物阴影、树木遮挡、水体反光都会成为误检来源。 项目说明里一般会写清楚这些信息。如果没有你需要自己做一个最基本的统计写一段脚本对训练数据里的所有标注框计算宽高分布看看绝大多数目标落在什么尺度范围。这个分布直接决定了你在配置里该用什么锚框尺寸、模型输入分辨率该设多大。不做这个统计直接硬套默认参数等于蒙着眼睛调模型后面全靠玄学。python import os import cv2 import numpy as np label_dir data/labels widths, heights [], [] for fname in os.listdir(label_dir): if not fname.endswith(.txt): continue img_path os.path.join(data/images, fname.replace(.txt, .jpg)) if not os.path.exists(img_path): # 可能你的影像不是 jpg自己按实际扩展名改 continue h, w cv2.imread(img_path).shape[:2] with open(os.path.join(label_dir, fname)) as f: for line in f: parts line.strip().split() if len(parts) 5: continue # 跳过格式不正确的行 # YOLO 格式: cls x_center y_center w h归一化 box_w float(parts[3]) * w box_h float(parts[4]) * h widths.append(box_w) heights.append(box_h) widths np.array(widths) heights np.array(heights) print(f框数量: {len(widths)}) print(f宽度: p50{np.median(widths):.1f}, p95{np.percentile(widths, 95):.1f}) print(f高度: p50{np.median(heights):.1f}, p95{np.percentile(heights, 95):.1f})这段脚本的输出结果是后面所有参数设置的事实依据。如果 p50 宽度是 20 像素p95 是 100 像素说明你的模型输入分辨率设为 640 就够了因为目标本来就不大如果 p95 是 500 像素说明你的影像里可能有大型目标需要把输入分辨率提高到 1024 甚至 1280否则大目标会被缩得太小丢失细节。这个统计还有个用处就是检查标注里是否有异常框——如果出现宽度等于整个图片宽度的框通常是标注时操作失误这种脏数据会在训练时产生巨大干扰。3. 把模型跑起来推理流程、参数含义与第一张检测图3.1 推理入口长什么样用自带权重跑通第一张遥感图环境没问题、数据也看过了下一步是用项目自带的模型权重跑推理。大多数这类项目会提供 best.pt 或类似命名的权重文件推理入口在 detect.py 或 inference.py。先别急着改成自己的数据先用项目自带的示例影像跑一遍确认环境、权重和代码三者匹配。这里给出一个通用的推理脚本模板可以直接对照项目源码看它缺了什么、改了什么。pythonsrc/detect.py 的简化版模式对应的核心调用逻辑import torch import cv2 import numpy as np加载模型model torch.hub.load(ultralytics/yolov8, custom, pathmodels/best.pt) model.eval()读取遥感影像img cv2.imread(data/images/example.tif) # 注意 TIF 可能要用 rasterio 读 img_rgb cv2.cvtColor(img, cv2.COLOR_BGR2RGB)推理results model(img_rgb, conf0.25, imgsz1280)后处理结果里每个框对应一个目标boxes results[0].boxes if boxes is not None: for box in boxes: x1, y1, x2, y2 box.xyxy[0].tolist() conf float(box.conf[0]) cls int(box.cls[0]) print(f类别 {cls} 置信度 {conf:.2f} 坐标 ({x1:.1f}, {y1:.1f}, {x2:.1f}, {y2:.1f}))这段代码里有三个参数值得关注conf 是置信度阈值低于这个值的检测结果会被丢弃imgsz 是输入网络的图像尺寸遥感影像会被缩放或填充到这个尺寸model.eval() 是切换到推理模式影响的是 BatchNorm 层的行为漏掉这一步会在结果里出现诡异的波动。实际项目中完整的 detect.py 还会包含结果可视化、保存到文件的逻辑但核心就是这三行。 代码背后的逻辑我要强调一下results[0].boxes 拿到的坐标是原图坐标而不是缩放后的坐标这个好理解但要注意 xyxy 是像素坐标如果你的遥感影像带地理坐标这个坐标没法直接用于 GIS 定位。需要转换的话常见做法是记录原影像的地理变换参数来自 GDAL 的 geotransform然后用像素坐标去反算经纬度后面第 6 章会展开。 ### 3.2 三个必调参数置信度阈值、IoU 阈值和输入分辨率 推理结果不理想不要怀疑权重文件有问题先检查你的参数设置。遥感目标检测里最常调的就是三个参数每个都有自己的门道。 置信度阈值 conf 控制漏检和误检的平衡。设得太低比如 0.05图上的每一块云、每一片阴影都可能是目标结果里全是框设得太高比如 0.7真实目标被过滤掉一半。遥感影像背景复杂我一般从 0.25 开始然后根据结果逐步调高或调低。如果你做的是船只检测目标轮廓清晰和背景对比大可以调高到 0.4如果做车辆检测目标小且与路面颜色接近可能得降到 0.15 才能保证召回率。 IoU 阈值用于非极大值抑制控制重叠框的合并策略。默认 0.45 通常够用但如果你的影像里目标密集比如港口里的船只一艘挨一艘重叠度高的真实目标会被合并掉一个这时候需要降到 0.3。反过来如果你的目标是厂房这样的大型建筑框之间的重叠本来就不大可以把 IoU 提到 0.6 减少重复框。 输入分辨率 imgsz 对遥感检测的影响远大于自然图像。模型权重在训练时用什么分辨率推理时最好保持一致否则检测精度会明显下降。但遥感影像往往远大于这个分辨率比如一张 8000×8000 的影像直接塞进模型会被暴力缩放到 1280汽车这样的目标直接从 40 像素变成 6 像素根本检测不到。解决办法有两个要么对原始影像做切片推理把大图切成 1280×1280 的瓦片逐块检测后合并结果要么把输入分辨率调大比如 1536 或 2048代价是显存占用和推理时间直线上升。我一般优先用切片方案后面第 6 章会讲具体做法。 ### 3.3 推理结果的验证思路别只看框要看错在哪 跑通第一次推理只是万里长征第一步关键是要会看结果的质量。直接把检测结果画在图上人眼检查这是最靠谱的验证方式没有之一。看的时候重点不是“有没有检测到目标”而是“漏掉了什么”和“多框了什么”。 漏检的类型能告诉你数据集的问题如果小目标大面积漏检说明输入分辨率不够或者模型本身对小目标不敏感如果一个特定方向的目标总是漏比如南北朝向的车辆能检测到、东西朝向的总是漏说明训练数据里朝向分布不均匀。误检的类型则更有意思如果你发现模型的误检集中在阴影区域那你需要补充带阴影的正样本让模型学会区分“影子里的车”和“只是影子”如果误检集中在植被区域通常是因为训练数据里没有足够的植被负样本。 如果项目说明里没写数据集的负样本数量建议你自己统计一下在所有训练图片里完全没有标注框的图片占总量的比例。如果这个比例很低说明模型没怎么见过“空的”场景推理时就更倾向于在空白区域产生误检。这个问题的补救方法是在训练时往数据里混入一批纯背景图标签为空让模型学会克制。 ## 4. 遥感检测的常见坑我得花两段话把踩过的坑都讲了 遥感目标检测这个方向模型本身的坑反而不多真正的坑全在数据和工程环节。我把这几年在这个方向上踩过的坑按“现象 → 原因 → 解决”的格式写出来每条都值得你在自己的项目里提前预防。 **坑一训练和验证精度都很高一到新影像上就一塌糊涂** 这个现象让人非常崩溃。原因几乎可以肯定是数据集偏差也就是训练影像和测试影像来自不同的传感器、不同的季节或不同的地区。同一个城市的夏季影像和冬季影像在视觉上差距极大夏季的车辆被树冠遮挡冬季的车辆周围全是枯枝模型学到的特征在冬季场景里根本不成立。 解决思路是主动做“域适应”而不是被动接受。把模型拿到的第一批新数据里表现最差的那些样本挑出来人工标注混入训练集做一轮增量训练。不要试图收集几千张图推荐的做法是每一轮增量训练只挑 100 到 200 张最有代表性的失败样本迭代三轮就有效果。 **坑二检测大图时显存直接爆掉** 这个现象就是前面提到的大图切片问题。8000×8000 的影像直接送进模型GPU 显存根本扛不住进程直接报 CUDA out of memory 被系统杀死。 原因在于把整张大图缩放后送进网络或一次性切太多块并行推理。正确做法是把大图切成 1280×1280 的瓦片每个瓦片之间有 10% 到 20% 的重叠区推理完再把结果映射回原图坐标。重叠区是为了防止目标正好被切在瓦片边缘导致只检测到一半后处理时对重叠区的重复检测框用 IoU 合并。显存实在紧张就串行切片逐个推理速度慢一点但不会崩。切片策略我在第 6 章给出完整代码。 **坑三模型的检测框偏小或偏大** 这个现象比较微妙框确实框住了目标但明显不贴合目标边界。在遥感影像里这通常不是模型的问题而是训练标签的标注质量不一致有些人标注喜欢紧贴目标有些人喜欢留出余量。模型学习的是训练标签的“平均松紧程度”所以推理结果也继承了这种不一致。 解决方法是看训练数据里的标注质量把明显偏松的框手动修正。如果脏标注太多与其修复不如直接过滤掉那些面积异常大的框。遥感标注本来就费劲如果标注不统一对模型精度的伤害极大。 **坑四推理结果在瓦片边缘大量漏检** 这个现象很隐蔽中间区域的检测结果都正常但切片的边缘地带老是漏检。原因前面提过就是目标被切成两半无法被识别为一个整体。解决方法是瓦片之间设置足够大的重叠区车辆、船只这种小目标重叠区 50 像素就够但如果是建筑或飞机这种大目标重叠区至少要到目标尺寸的一半。另一个技巧是边缘抑制对瓦片边缘检测出来的低置信度框先不着急丢弃放到整张大图的坐标体系里再看一次如果它能和邻近瓦片的某个检测结果重叠合并成一个高置信度的框说明它是被切了一半的目标应当保留。 **坑五项目说明文档说支持 GPU 但训练还是慢** 这个现象好理解装上了 GPU 版本的 PyTorch但训练时发现 GPU 利用率只有 20%。常见原因是数据加载瓶颈CPU 读图、解码、做数据增强的速度跟不上 GPU 的算力。解决方法是把 batch_size 调大同时把数据加载的 num_workers 从默认的 2 调到 8 或更高。还有一个容易忽略的原因数据增强里如果包含大尺寸随机裁剪之类的重操作也会拖慢数据加载。先关掉数据增强跑一分钟看速度再逐步打开每项增强定位是哪个操作拖慢了整体速度。 ## 5. 从推理到训练用自己的数据把模型调成自己想要的样子 ### 5.1 标注格式转换遥感影像标注的第一步是把框从一种格式搬到另一种格式 预训练模型只能帮你跑通流程要真正适配你自己的场景重新训练是必须走的一步。而训练的第一步是把你手里的标注数据转换成模型需要的格式。 遥感领域最常用的标注工具是 LabelMe 和 QGIS导出的格式各不相同。LabelMe 导出 JSON里面存的是多边形顶点坐标QGIS 可以导出 GeoJSON 或 Shapefile。而 YOLO 系列需要的标注格式是「每张图片一个同名 txt 文件每行一个目标内容是 class x_center y_center width height且都是归一化的坐标」。这个转换过程不复杂但很琐碎容易出现精度损失。 下面这个脚本处理的是 LabelMe JSON 转 YOLO 格式的常见场景多边形会先转成外接矩形再归一化。python import json import os from PIL import Image def labelme_json_to_yolo(json_path, output_dir, class_names): with open(json_path, encodingutf-8) as f: data json.load(f) img_path data[imagePath] img Image.open(os.path.join(os.path.dirname(json_path), img_path)) img_w, img_h img.size # 输出 txt 文件名与图片同名 base_name os.path.splitext(img_path)[0] out_txt os.path.join(output_dir, base_name .txt) with open(out_txt, w) as f: for shape in data[shapes]: label shape[label] if label not in class_names: continue cls_id class_names.index(label) points shape[points] # [[x1,y1], [x2,y2], ...] xs [p[0] for p in points] ys [p[1] for p in points] x_min, x_max min(xs), max(xs) y_min, y_max min(ys), max(ys) x_center (x_min x_max) / 2 / img_w y_center (y_min y_max) / 2 / img_h box_w (x_max - x_min) / img_w box_h (y_max - y_min) / img_h f.write(f{cls_id} {x_center:.6f} {y_center:.6f} {box_w:.6f} {box_h:.6f}\n) # 用法示例 class_names [car, ship, plane] labelme_json_to_yolo(data/labelme/img001.json, data/labels, class_names)这个脚本里有几个容易出错的地方第一是class_names列表的顺序必须和dataset.yaml里的顺序完全一致否则类别 ID 就错位了训练出来的模型会把车识别成船第二是归一化坐标YOLO 格式要求所有框的坐标值都在 0 到 1 之间如果影像里存在跨边界的特殊情况需要特殊处理下一步避坑第三是 LabelMe 的 JSON 里可能包含group_id等字段不影响转换但记录了不同目标的组合关系如果后面要做实例分割可以留用。5.2 数据划分训练集、验证集、测试集的分配不是随便切一刀数据划分这件事很多人直接交给训练框架默认处理在遥感任务里不建议这样。遥感影像普遍存在空间自相关性同一景影像内相邻区域的目标外观高度相似。如果随机划分和训练集聚类在一起的验证集图片可能过于相似导致验证精度虚高。正确做法是按影像来源划分确保同一景影像的切片全部进了同一边不能一部分在训练集一部分在验证集。具体的比例我一般用 7:2:1训练 70%验证 20%测试 10%。测试集必须保证模型在训练时绝对没有见过只用于最终评估。验证集在训练过程中会反复被模型观察通过调整超参数影响训练所以它不是一个干净的评估基准。如果你手里的标注数据量不足 200 个框直接训练小模型基本上没戏。这时候需要借助预训练模型做迁移学习固定住主干网络只训练检测头用少量数据也能稳住基本盘。这是遥感标注数据稀缺时最实用的一招不要小看它。5.3 训练参数学习率、批次大小和训练轮数的选择逻辑模型训练的参数设置直接决定你能否收敛到一个可用的结果。遥感目标检测的训练参数和自然图像大体一致但有一个额外变量数据量。这里给出一个我已经验证过多次的 YOLO 系列训练参数配置模板可以直接拿来参考。yamldataset.yaml 示例放在项目根目录下path: . train: data/images/train val: data/images/valnc: 3 names: [car, ship, plane]训练命令以 YOLOv8 为例其他 YOLO 版本大同小异。bash # 从预训练权重继续训练而不是从零开始 yolo train datadataset.yaml modelyolov8n.pt epochs100 batch16 imgsz640 lr00.001几个关键参数的含义和调整方向说一下。lr0是初始学习率迁移学习场景推荐 0.001从头开始训练推荐 0.01。数据量越小学习率应该越低避免模型大步跨越把预训练学到的特征冲掉。batch的大小受显存限制遥感影像一般比较大如果imgsz640时 batch16 都放不下考虑改用 320 的输入尺寸或者混精度训练 fp16。epochs不要死板设置成 100 轮但实际上用早停法一般最好的权重出现在第 50 到 80 轮之间过了这个区间模型开始在训练集上过拟合验证精度停滞甚至下降。另外设置cos_lrTrue可以启用余弦退火学习率调度实践下来比阶梯式下降更平稳尤其是数据量小的时候。patience20是早停参数意思是验证精度连续 20 轮没有提升就停止训练自动保存最好的权重。这些参数在训练脚本里都有对应配置如果你用的项目包封装程度更高可能在 config.py 里。训练过程中要盯的关键指标其实是val/object_loss和val/box_loss这两条曲线而不是总精度。这两个 loss 如果持续下降说明模型还在学到有用的东西如果 object_loss 不降反升大概率是模型对背景的误判越来越多要去检查标注里是否有大量漏标的目标——漏标的目标在模型看来就是背景模型会尝试把它们学成背景和标注信息冲突loss 自然就压不下去。5.4 训练结果解读权重文件的选择没有“最好的那个”训练结束后输出目录里会有 best.pt 和 last.pt 两个文件best.pt 是验证精度最好的一轮last.pt 是最后一轮。对于大多数遥感项目我用 best.pt 而不碰 last.pt。除非你是想继续训练而不是部署last.pt 才有用。还有一个容易踩到的点训练框架的验证集精度计算方式和推理时不完全一致。训练时的验证集精度是在训练阶段通过评估得到的包含了一些数据增强和模型尚未完全稳定的中间状态而部署推理时模型是稳定的所以最终上线效果才以直接推理测试为准。跑完训练拿到 best.pt 后一定要单独拿一批绝对没参与过训练和验证的影像做最终测试这一步不可省。如果你有多个模型做比较把不同模型的权重在同一组测试集上做对比指标只看 mAP50 和 mAP50-95。mAP50 代表“框位置大概对上就行”的精度mAP50-95 则要求框的位置非常精确遥感目标检测里车辆、船只这种小目标建议两个指标一起看不能只看 mAP50否则模型可能学出一堆位置飘忽不定的“大概是车”的框。6. 大图推理的工程化进阶切片检测与坐标回映射的完整方案遥感影像推理的最后一公里始终是大图怎么处理。一张 8000×8000 的影像直接送进模型是肯定不行的工程上最稳定的方案就是切片检测。推荐用 40% 的切片重叠率处理步骤如下先把大图切成多个 1280×1280 的瓦片瓦片之间保持 20% 的像素重叠然后对每个瓦片做标准推理把瓦片坐标下的检测框映射回原图坐标最后对所有框做一次全局的 IoU 合并把不同瓦片重叠区域里重复检测的框合并为同一个。def sliding_window_detect(model, img, window_size1280, overlap0.2, conf0.25): 大图切片推理返回所有检测结果坐标为大图像素坐标。 import numpy as np import torch h, w img.shape[:2] stride int(window_size * (1 - overlap)) boxes_all, scores_all, cls_all [], [], [] for y in range(0, h, stride): for x in range(0, w, stride): # 确保最后一个瓦片不会超出边界超出部分做边缘截断 y2 min(y window_size, h) x2 min(x window_size, w) crop img[y:y2, x:x2] if crop.shape[0] 32 or crop.shape[1] 32: continue # 推理 results model(crop, confconf, imgszwindow_size) boxes results[0].boxes if boxes is None: continue # 映射回大图坐标 for box in boxes: bx1, by1, bx2, by2 box.xyxy[0].tolist() boxes_all.append([bx1 x, by1 y, bx2 x, by2 y]) scores_all.append(float(box.conf[0])) cls_all.append(int(box.cls[0])) return np.array(boxes_all), np.array(scores_all), np.array(cls_all)这个函数有三个要点。第一overlap0.2是重叠率而不是重叠像素如果你的目标特别大或特别密集建议提升到 0.3 甚至 0.4重叠率越大推理时间越长漏检率越低。第二瓦片边缘的检测框置信度普遍比中心低因为目标被截断了所以切片推理的conf阈值要设置得比整图推理低一些比如整图用 0.3切片用 0.2先把目标找出来后面用全局合并消除误检。第三results返回的坐标是瓦片内的像素坐标必须加上瓦片左上角的偏移量(x, y)这个偏移量很容易忘记加漏了的话后面所有框都错位。这里要提醒一个深坑送进模型的瓦片尺寸和模型输入尺寸要保持一致。如果模型配置imgsz1280你切了 1280 的瓦片喂进去模型会把瓦片缩放回 640 再处理。但如果你切了 1600 的瓦片模型会先缩放到 1280 再推理相当于在瓦片维度上又做了一次缩放小目标信息在这个过程里又丢了一层得不偿失。切片推理完成后还有一个容易忽略的工作可视化结果时必须把框画回到原图上这一步用 OpenCV 的rectangle函数循环绘制就行但要注意绘制的框坐标必须用回映射后的大图坐标。保存可视化结果时我建议同时保存一张纯框线图和一张带透明度的叠加图前者给算法工程师看检测结果后者给标注人员做人工复核参考。如果目标要落到 GIS 里使用还需要把像素坐标换算成地理坐标。这一步依赖于原始影像的地理变换参数常见做法是读取 TIF 的 geotransform 数组包含六个参数左上角 X 坐标、东西方向像素分辨率、旋转角、左上角 Y 坐标、南北方向像素分辨率、旋转角。像素坐标转地理坐标的公式是X_geo geotransform[0] pixel_x * geotransform[1] pixel_y * geotransform[2]Y_geo geotransform[3] pixel_x * geotransform[4] pixel_y * geotransform[5]。写代码时注意 geotransform 的索引顺序不要搞反。我自己做遥感目标检测项目时有一条坚持了很久的习惯是每一个正式交付给下游的检测结果都必须附带一份“检测置信度分布图”所有目标的置信度画成直方图如果分布呈双峰形状说明有一批目标的质量明显低于另一批这时候就要去排查数据分布差异了。这个习惯帮我提前暴露过好几次问题比直接看 mAP 指标靠谱得多。遥感图像目标检测这个方向做好数据预处理就等于完成了 70% 的工作。模型选择可以往后放数据质量、标注一致性、切片策略这三件事是决定最终效果的核心。如果拿到这个 zip 包后你能把每一步的数据都亲眼看一遍跑通之后的调优之路会顺畅很多。希望这些实践经验和踩坑记录能帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑