☰
遥感图像小目标检测实战:从数据切图到YOLOv8模型训练与GIS落地
2026/10/2 2:43:23 网站建设 项目流程

简介:面向毕业设计、课程设计、课程大作业及遥感目标检测入门进阶的Python实现源码与模型包,基于FAIR1M2.0遥感监测数据集训练,完整覆盖环境安装、数据集整理、模型推理、结果分析与项目说明,可用于项目复现、二次开发或初期方案演示。压缩包共404个文件,以350个Python脚本为主体,包含检测、训练、推理和工具脚本;22个YAML配置文件负责模型结构、训练超参与数据路径等参数管理;22个Markdown文档提供项目说明、配置说明与模型说明,另有CSV、IPYNB、TXT等文件支撑结果分析与实验复现,整体约7.54MB。已有729人浏览学习。特别适合计算机、人工智能、通信工程、自动化、电子信息等专业学生用于毕设、课设或初期项目演示;代码经测试可运行,并附有FAIR1M2.0数据集的train_color、train_gray预处理与目录组织说明,方便快速迁移到自有数据。基础较好的读者还可基于此代码修改扩展,实现自定义遥感目标检测功能。

1. 遥感图像物体目标检测,这份源码+模型+项目说明的zip该怎么用

把这份基于python实现遥感图像物体目标检测的zip解压之后,你面前大概率是三类东西:一整套能跑的python源码、训练好的模型权重文件、一份项目说明文档。遥感目标检测和普通目标检测最大的差别在于目标小、方向任意、背景复杂,直接把自然场景的检测流程搬过来,mAP往往惨不忍睹。这份zip的价值不在于代码本身有多惊艳,而在于它把"数据准备—模型训练—推理评估"这条链路预先串好了。你要做的不是从零搭环境,而是理解这条链路、替换成自己的数据再跑起来。

这篇笔记适合两类人:遥感专业的硕士生,以及想把检测能力接进GIS工作流的工程师。前者需要快速出结果,后者需要稳定可交付的产出。我会按拆包、数据准备、训练、推理避坑、结果落地的顺序,把这份项目包从里到外讲透,并附上可以直接抄走的脚本和参数。文中提到的文件路径和命令都按最常见的YOLO系遥感项目写法来,具体命名以你手里的zip为准。

2. 把zip包拆开看:源码、模型权重与项目说明的分工

拿到zip先别急着train,先花十分钟把家底盘清楚。这一步决定你后面是顺畅复现还是反复翻车。项目包里每个文件都有它的用途,混着用会出大问题。

2.1 源码目录结构:train、detect、val三剑客,以及辅助模块怎么认

一个典型的遥感目标检测项目,代码量通常不大,核心入口只有三个:train.py负责训练,detect.py负责推理,val.py负责评估。剩下的models、utils、data目录是辅助模块。我拿到zip的第一步不是读代码,而是先看项目说明,确认它基于哪个检测框架——YOLO系还是Faster R-CNN,标注格式是VOC、COCO还是YOLO的txt。这个判断直接决定后面所有数据准备工作往哪个方向走。

常见目录结构大概是这样的:

project_root/ ├── train.py # 训练入口 ├── detect.py # 推理入口 ├── val.py # 评估入口 ├── models/ # 网络结构定义 ├── utils/ # 数据加载、loss、指标工具 ├── data/ │ ├── images/ # 原始遥感影像 │ └── labels/ # 标注txt/xml ├── weights/ │ ├── best.pt # 验证集最优权重 │ └── last.pt # 最后一轮权重 └── 项目说明.md

注意观察train.py和detect.py是否独立。如果zip里只有detect.py没有train.py,那它大概率只是一个推理demo,训练脚本得自己补;反过来,如果models目录下缺了网络定义文件,训练一启动就会报ModuleNotFoundError。这种结构性检查五到十分钟就能做完,省掉的是后面一整天排错时间。

数据目录里如果images和labels各有一份且数量对得上,说明作者至少跑通过一遍全流程,这种包的可信度会高很多。如果只有images没有labels,那数据准备工作要从头做起,别指望训练脚本能自动标注。

2.2 模型权重怎么认:pt、pth、onnx三种格式的适用场景

权重文件是项目里最容易被误用的一块。同样是"模型",后缀不一样,使用方式完全不能混。遥感目标检测项目里最常见的三种格式差别很大:

后缀来自哪个生态能不能直接推理典型用途
.ptPyTorch/YOLO能,但依赖原项目网络定义用best.pt做迁移学习起点
.pth纯PyTorch保存取决于保存的是state_dict还是整模型配合原模型类加载
.onnx跨平台中间格式能,且不依赖训练框架部署到CPU/边缘设备

判断权重能不能用的土办法:看项目说明里写的是"预训练权重"还是"微调权重"。预训练权重一般是在COCO或ImageNet上训出来的,用途是当迁移学习的起点;微调权重是用遥感数据训出来的,可以直接拿来推理。如果说明文档只写"下载权重"没写来源,先用一张带明显目标的遥感大图跑一次detect.py验证,输出的框靠谱再当正式权重用。

很多坑出在格式上。.pt和.pth看起来都是PyTorch文件,但.pt权重在加载时必须能找到与训练时一致的网络结构定义(models/yolo.py),版本对不上就报尺寸不匹配。.onnx则不需要原始网络定义,只要输入尺寸对得上就能跑,这也是为什么我看到很多人做生产环境部署时都会额外导出一份onnx权重。

2.3 项目说明文档先看哪三节:环境依赖、数据格式、训练命令

项目说明文档很多人解压后直接跳过,这是坏习惯。它有明确的阅读顺序:先看环境依赖,再看数据格式,最后看训练命令。环境依赖决定你能不能把程序跑起来,数据格式决定你的标注要不要重做,训练命令决定你用多大代价复现结果。

环境依赖这块,最稳妥的是项目里带了requirements.txt:

pip install -r requirements.txt

装之前先确认两件事:Python版本和PyTorch版本。遥感目标检测项目常用Python 3.8到3.11,PyTorch 1.8到2.x。如果项目要求的torch版本和你本机CUDA版本不匹配,会出现"torch.cuda.is_available()返回False"这种典型问题。这时候不要盲目重装,先确认python安装时的版本适配,再按CUDA版本选对应的安装命令。python环境配置是这里最常见的翻车点,很多人卡在这一步一整天。

数据格式部分要看清楚标注是水平框还是旋转框。水平框的标签文件里每行是"类别id 中心x 中心y 宽度 高度",旋转框会在后面多一个角度值。格式看错,整个训练白跑。

2.4 最小运行验证:一条命令把detect.py跑通

正式训练之前一定先把推理跑通。这一步能验证环境、权重、数据读取链路是否正常,也让你直观看到模型的检测效果。最小推理命令通常长这样:

python detect.py --weights weights/best.pt --source data/images/0001.tif --img-size 640

参数说明:--weights指定权重路径;--source是输入影像路径,单张图、文件夹都行;--img-size是推理尺寸,遥感影像建议640起步,太小会丢小目标。如果项目用YOLOv5系列,命令基本一致;但注意YOLOv8里img-size改成了imgsz,传参名称对不上会直接报unexpected argument。

如果这一步报错,优先看三点:权重路径是否存在、detect.py里import的模型模块是否能找到、输入图片路径是否含中文。中文路径会让OpenCV读图失败,这是国内开发者踩得最多的坑,把data目录全部改成英文路径,90%的文件读取问题直接消失。

跑通之后,output目录会生成带检测框的标注图。看到框的位置基本正确,说明整个项目的链路已经打通,这时候研究训练和调参才有意义。

3. 遥感图像数据准备:从原始影像到可训练的标注集

数据准备是遥感目标检测里最枯燥但最重要的环节。模型结构决定精度上限,数据质量决定能不能逼近这个上限。这一章把数据集选型、标注工具、切图、格式转换一次讲清楚。

3.1 遥感数据集选型:DOTA、RSOD、HRSC2016怎么选

遥感目标检测起步阶段,最好先别用自己的数据,用成熟的开源数据集把流程跑通最划算。行业里常用的三个数据集各有偏向,选哪个取决于你的项目目标。

数据集类别数标注形式适合场景
DOTA15旋转四边形通用多类检测、算法对比
RSOD4水平矩形框流程验证、小样本调参
HRSC20161旋转矩形框船只专项、方向框研究

DOTA是航空影像中规模最大的检测基准,包含飞机、车辆、船只、储油罐、桥梁等15个类别,标注是带旋转角度的四边形框,适合做通用遥感目标检测的起点。RSOD规模小但类别干净,只有飞机、操场、立交桥、船舶四类,适合快速验证流程。HRSC2016专注船只检测,图像来自不同分辨率,适合做单一类别精细化检测。

选数据集时先看自己需求:如果做多类目标普查,DOTA最合适,但它单张图尺寸大,必须切图训练;如果只是验证源码能否跑通,RSOD最快,下载后基本不用清洗;如果项目要检测船只且要方向信息,HRSC2016的格式和DOTA相近,但类别单一,训练容易收敛。多数新手用RSOD入门,跑通后再换DOTA提精度,这条路线最省时间。

3.2 遥感图像标注工具:roLabelImg处理旋转框,LabelImg兜底水平框

标注工具的选择完全取决于模型支持哪种框。YOLO系列默认输出水平矩形框,训练数据只要四个坐标值。但遥感场景里船只、飞机往往斜着排列,水平框会框进大量背景,模型学起来很吃力。

如果项目说明里写了支持旋转框,标注工具选roLabelImg,它能画带角度的矩形框并输出旋转坐标。如果项目只支持水平框,LabelImg就够了,它导出的VOC xml或YOLO txt是通用格式。这里要特别提醒:不要把旋转框和水平框混在一个数据集里标。同一批数据里既有旋转框又有水平框,标注解析脚本会读取到不一致的字段,训练时loss异常你根本查不出原因。

我在这上面吃过亏——用roLabelImg标了200张图,结果发现模型只支持水平框,全部重标,白白浪费两天。所以标注前一定先确认模型能力,而不是先动手标。工具本身都是免费开源的,重点不在工具,在与模型匹配。

3.3 滑窗切图参数怎么设:小目标检测的前提操作

遥感影像动辄几千乘几千像素,直接整图喂给GPU不现实,目标在整图里占比也小得可怜。滑窗切图是遥感目标检测的基础操作,把大图切成模型输入尺寸的子图,目标在子图里所占比例变大,模型才能学得到。

import cv2 from pathlib import Path def sliding_window_crop(image_path, output_dir, crop_size=608, stride=304): img = cv2.imread(str(image_path)) h, w = img.shape[:2] img_name = Path(image_path).stem count = 0 for y in range(0, h - crop_size + 1, stride): for x in range(0, w - crop_size + 1, stride): crop = img[y:y+crop_size, x:x+crop_size] # 子图命名里带上左上角坐标,方便后续坐标还原 cv2.imwrite(f"{output_dir}/{img_name}_{x}_{y}.jpg", crop) count += 1 # 处理右边缘和下边缘的剩余区域,避免目标被切没 if w % crop_size != 0: cv2.imwrite(f"{output_dir}/{img_name}_{w-crop_size}_{0}.jpg", img[0:h, w-crop_size:w]) if h % crop_size != 0: cv2.imwrite(f"{output_dir}/{img_name}_{0}_{h-crop_size}.jpg", img[h-crop_size:h, 0:w]) print(f"切出 {count} 张子图")

crop_size和stride是切图两个核心参数。crop_size取608或640,和模型输入尺寸对齐;stride取crop_size的一半,也就是重叠率50%,这样目标落在切图边缘时至少有一张子图完整包含它。切图后目标相对变大,小目标漏检问题能缓解一半,这比调损失函数直接得多。

关键点在于:切图的同时必须同步切标注框,不能只切图不切标注。标注框被切边界截断时,要么丢弃,要么做边界截断处理。如果忽略这一步,训练时会出现大量gt框超出子图区域,loss直接跑飞。

3.4 标注格式转换:VOC转YOLO的脚本逻辑与边界坑

VOC格式(xml)和YOLO格式(txt)之间的转换是最高频操作,也是数据准备里最容易出暗病的一步。YOLO的txt每行是一个目标:类别id、中心点x、中心点y、宽度w、高度h,全部归一化到0到1之间。

import xml.etree.ElementTree as ET def voc_to_yolo(xml_path, class_names, output_path, img_width, img_height): tree = ET.parse(xml_path) root = tree.getroot() lines = [] for obj in root.iter('object'): name = obj.find('name').text if name not in class_names: continue class_id = class_names.index(name) bbox = obj.find('bndbox') xmin = float(bbox.find('xmin').text) ymin = float(bbox.find('ymin').text) xmax = float(bbox.find('xmax').text) ymax = float(bbox.find('ymax').text) # 归一化,中心点坐标除以图像宽高 x_center = ((xmin + xmax) / 2) / img_width y_center = ((ymin + ymax) / 2) / img_height w = (xmax - xmin) / img_width h = (ymax - ymin) / img_height # 截断到[0,1],防止坐标越界导致训练异常 x_center = min(max(x_center, 0.0), 1.0) y_center = min(max(y_center, 0.0), 1.0) w = min(max(w, 0.0), 1.0) h = min(max(h, 0.0), 1.0) lines.append(f"{class_id} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}") with open(output_path, 'w') as f: f.write('\n'.join(lines) + '\n')

这里的三个边界坑必须注意。第一,如果xml里的坐标是切图前的绝对坐标,而图像已经切过,必须先换算到切图子图的局部坐标再归一化,直接用原图宽高计算会得到完全错误的标签。第二,类别名必须和class_names列表的顺序完全一致,顺序错了模型训练出来类别全错,而且这种错误在loss曲线上看不出来,只能在验证集上发现。第三,没有目标的图片也要生成空txt文件放在同目录,很多训练脚本按图片名索引标签文件,缺了会报KeyError。

转换完一定要抽几张图可视化验证,把txt标签画回图上对比原标注。不要只看文件生成了就觉得没问题,坐标偏差几个像素在家用场景无所谓,在遥感尺度下可能意味着几十米的偏差。

4. 模型训练:YOLOv8在遥感场景下的配置与调参

数据准备好之后进入训练阶段。模型选型和参数配置直接决定训练效率和最终精度。这一章讲清楚为什么遥感场景默认选YOLOv8,以及训练时最关键的参数怎么调。

4.1 为什么遥感场景默认选YOLOv8而不是Faster R-CNN

遥感目标检测项目里出现过的模型骨架很多:Faster R-CNN、SSD、YOLOv5、YOLOv8,最近还有DETR系。但在工程落地层面,我一般首选YOLOv8。原因不是它精度最高,而是生态最完整。Ultralytics框架把数据加载、训练、验证、导出ONNX全封装好了,网上踩坑记录多,改起来阻力最小。

Faster R-CNN的两阶段结构在遥感小目标上确实有精度优势,但训练速度慢、显存占用高、调参敏感,对新手不友好。YOLO单阶段检测速度快,配合合理的切图策略,精度差距已经缩小到可以接受的程度。遥感目标检测的瓶颈往往在数据质量而非模型结构,把YOLOv8训好比纠结用哪个SOTA结构收益高得多。

如果你拿到的zip是YOLOv5写的,不用急着换,v5和v8的数据格式、训练流程基本一致,迁移成本很低。版本不是第一位的,能跑通才是第一位的。先把手里的项目跑起来,再考虑升级框架。

4.2 训练命令与五个必调参数:batch、img-size、epochs怎么配

训练命令通常长这样:

python train.py --data dataset.yaml --weights yolov8n.pt --epochs 150 --batch-size 16 --img-size 640 --device 0

dataset.yaml是数据集的配置文件,里面写训练/验证图片路径和类别名列表。五个必调参数是epochs、batch-size、img-size、device和workers。

epochs遥感场景一般100起步,数据量大到几千张图时150到300不夸张,关键是看val loss是否还在下降。batch-size受显存限制,12G显存跑YOLOv8n可以到32,跑YOLOv8m建议降到8到16。低显存运行模型时优先降低batch而不是降低图片尺寸,batch太小会引入噪声,但总比显存溢出强。img-size是训练分辨率,遥感小目标建议640到1024,但注意分辨率和显存占用是平方关系,1024的显存开销是640的2.56倍。device 0是第一块GPU,没有GPU就写cpu,训练速度会慢两个数量级。workers是数据加载线程数,Windows下超过4容易报DataLoader worker崩溃,Linux可以设到CPU核心数的一半。

dataset.yaml是关键文件,给一个经过实践验证的模板:

# dataset.yaml train: data/images/train val: data/images/val nc: 5 names: ['airplane', 'ship', 'vehicle', 'storage_tank', 'bridge']

nc是类别数,names顺序必须和第3章里提到的class_names顺序保持一致。这个一致性是训练不出错的前提,顺序错了,模型学到了正确的特征却输出到错误的类别id上。

注意:dataset.yaml里的类别顺序一旦确定,后续所有标注转换脚本里的class_names都要跟着它走。这个顺序问题在训练时不报错,只在评估时发现mAP异常,排查起来很费时。

4.3 小目标漏检的针对性措施:浅层特征图与切图互补

遥感影像里的目标常只有几十个像素,模型下采样四次后,小目标在特征图上可能只剩一两个像素,漏检几乎必然。这里有两个主流做法:启用更浅层的检测头,或者进一步切图放大目标。

浅层检测头(常说的P2层)分辨率更高,保留更多小目标细节,但会显著增加计算量,而且对新手来说修改模型配置偏硬核。更务实的做法是回到第3章的滑窗切图——把图像切成640子图训练,目标在子图里占的比例变大,模型更容易学。两者可以叠加,切图加浅层检测头,时间充裕就都上。

另一个常用技巧是mosaic增强,Ultralytics默认开启,把四张图拼成一张训练图,对小目标有利。但要注意,遥感影像的特征和大自然图像差异大,mosaic过度可能导致模型学到拼接边界纹理。如果训练中mAP迟迟不涨,可以尝试关闭mosaic换成简单增强。

4.4 训练日志监控:loss曲线和mAP曲线哪些信号说明模型学歪了

训练起来后不要只盯着进度条,要保存并观察两条曲线:box_loss和mAP50。box_loss持续下降是正常信号,如果loss震荡不降,多半是学习率过大或数据标注有问题。mAP50在前30个epoch不涨是正常的,50个epoch还在0.1附近徘徊,就要考虑类别不平衡——某些类别样本极少,模型把所有框都预测成了多数类。

用现成的日志文件就能观察:

tail -f runs/train/exp/results.csv

results.csv里每一行是一个epoch的指标,包括train/box_loss、val/mAP50等。我一般用pandas直接读csv画曲线,比自己从终端复制数字可靠。如果val/mAP50涨到某个值后开始下降,而train/loss还在降,那就是过拟合信号,及早停止或加大数据增强,别让训练跑满全部epochs浪费GPU时间。

训练结束后,weights目录下会生成best.pt和last.pt。best.pt是验证集最优模型,后续推理和评估都用它。有些项目只保存last.pt,这种要小心,最后一轮可能已经过拟合,用它推理效果大概率不如best.pt。

5. 推理、评估与避坑:遥感目标检测的五个高频翻车点

模型训练完只是开始,推理和评估才是真正检验成果的地方。这一章把大图推理的坐标还原、评估指标的选择、以及遥感场景下最高频的四个翻车点一次讲清楚。

5.1 大图推理:TIFF切块、检测、坐标还原

遥感影像推理时不能把整张TIFF直接塞进模型。即使显存够,目标在整图里占比太小也检测不出来。标准做法是切块推理,再把子图的检测框坐标还原到大图坐标系。

from ultralytics import YOLO import cv2 def infer_large_image(model, large_img_path, crop_size=640, stride=320, conf_thres=0.3): img = cv2.imread(large_img_path) h, w = img.shape[:2] results = [] for y in range(0, h - crop_size + 1, stride): for x in range(0, w - crop_size + 1, stride): crop = img[y:y+crop_size, x:x+crop_size] preds = model(crop, conf=conf_thres, verbose=False) for box in preds[0].boxes: x1, y1, x2, y2 = box.xyxy[0].cpu().numpy() cls = int(box.cls[0]) conf = float(box.conf[0]) # 关键:子图坐标加滑窗起点还原到原图坐标 results.append((x1 + x, y1 + y, x2 + x, y2 + y, cls, conf)) return results

坐标还原是这段代码的灵魂:子图检测框的坐标必须加上滑窗起点才是原图坐标,漏掉这一步,检测结果全部错位。conf_thres在大图推理时不要设太低,遥感图像背景复杂,0.25置信度会产生大量误检,我一般从0.3起步再往下调。重叠区域可能出现同一目标被两张子图各检出一次,后处理里做NMS合并是必须的,否则最终结果看起来会有大量重复框。

5.2 评估指标:mAP50和mAP50:95在遥感场景怎么看

评价模型不能只看效果图,要看val.py输出的指标。mAP50是IoU阈值0.5下的平均精度,mAP50:95是从0.5到0.95每隔0.05取IoU算平均。遥感目标检测里优先看mAP50,原因在于旋转框和水平框的IoU天花板很低,方向略有偏差IoU就跌破0.75,mAP50:95数字会非常难看,但不代表模型不能用。如果项目要做精细测量,再回头细抠mAP50:95。

对比模型好坏时注意数据集和切图参数必须一致。很多人拿不同切图策略的效果直接比mAP,那是没有意义的。stride不同、切图尺寸不同,目标被切碎的概率不同,mAP天然不同。同一份数据、同一套切图参数下,才谈得上模型层面的对比。

5.3 高频翻车点:方向框丢失、小目标漏检、显存不足、类别不平衡

翻车点一:方向框全丢了。现象:模型推理输出只有水平框,训练时用roLabelImg标的角度信息完全没生效。 原因:项目里的模型是水平框检测模型,只读取xywh四个值,角度值被标注解析脚本忽略。 解决:确认模型是否支持旋转框检测头。不支持就把训练标签里的角度信息去掉,用水平框硬训;一定要方向框就换模型版本,不要指望水平框模型能输出角度,它做不到。

翻车点二:小目标漏检严重。现象:大目标检测正常,小目标(几十像素的车辆、船只)几乎全漏。 原因:小目标在特征图下采样后信息丢失,或者训练时切图没有覆盖到目标密集区。 解决:回到滑窗切图,缩小stride增加重叠率,并适当提升训练分辨率到960或1024。这两个手段通常能让小目标mAP大幅回升。

翻车点三:CUDA out of memory。现象:训练跑到某一步突然报显存溢出。 原因:batch-size和img-size的显存占用超出GPU容量,或者Windows下开了过多workers导致数据预加载占用额外显存。 解决:低显存运行模型时,优先把batch-size减半,其次把img-size从640降到512。切图尺寸本身决定输入上限,不要为了跑高分辨率硬上大batch。

翻车点四:类别不平衡导致检测结果偏科。现象:多数类(如车辆)检测精确率高,少数类(如桥梁)mAP接近0。 原因:训练集里类别样本数差距过大,模型学成了多数类检测器。 解决:给少数类做样本复制增强,或者按类别加权loss。最简单有效的是先把少数类的图片多复制几份,朴素但立竿见影。

5.4 低显存推理与部署:导出ONNX的实用配置

显存不够时不一定需要换机器。推理阶段用ONNX配合ONNX Runtime,CPU也能跑,但导出ONNX时要注意动态输入尺寸和固定尺寸的区别。

model.export(format='onnx', imgsz=640, dynamic=True)

dynamic=True允许输入尺寸动态变化,代价是推理速度下降;固定640速度最快,但切图尺寸必须配合。低显存场景还有个实用技巧:用half精度推理,显存占用几乎减半,精度损失在遥感大目标上不明显,但小目标要谨慎,先跑一遍验证集对比mAP,掉太多就别用。

6. 把检测结果落成产品:从像素框到GIS矢量的一个技巧

遥感检测的交付物不是一张画了框的图片,而是带地理坐标的矢量文件。这一章讲一个把检测结果输出为GeoJSON的实用做法,让结果能直接拖进QGIS验证,而不是停留在技术自嗨。

6.1 像素坐标转地理坐标:由bbox到GeoJSON

检测框的坐标是像素坐标,对遥感业务来说没有意义,地理坐标才是交付物。转换逻辑很简单:已知影像左上角经纬度和单像素对应的地面尺寸,就能把像素偏移量换算成经纬度偏移。

import json def bbox_to_geojson(results, transform_info): features = [] # transform_info 包含左上角经纬度 lon0, lat0 和分辨率 res(度/像素) for x1, y1, x2, y2, cls, conf in results: lon1 = transform_info['lon0'] + x1 * transform_info['res'] lat1 = transform_info['lat0'] - y1 * transform_info['res'] lon2 = transform_info['lon0'] + x2 * transform_info['res'] lat2 = transform_info['lat0'] - y2 * transform_info['res'] feature = { "type": "Feature", "properties": {"class": cls, "confidence": round(conf, 4)}, "geometry": { "type": "Polygon", "coordinates": [[[lon1, lat1], [lon2, lat1], [lon2, lat2], [lon1, lat2], [lon1, lat1]]] } } features.append(feature) return {"type": "FeatureCollection", "features": features}

经纬度换算时注意y方向符号。遥感图像通常北在上,像素y增加方向是向南,所以纬度用左上角纬度减去偏移量,加号写反会导致检测结果整体错位,而且这个错位不叠加底图肉眼很难察觉。res可以从TIFF的地理元数据里读,如果没有元数据只能手动输入,务必确认单位是度还是米。

6.2 与QGIS联动:直接加载检测结果验证

生成GeoJSON后,用QGIS直接拖进去,检测框套在卫星底图上的正确性一眼可见。这一步值得花时间,因为它是把结果交给业务方的最终形态。我自己的习惯是检测脚本输出bbox后紧接一步坐标换算,形成GeoJSON落盘,后续无论是跑统计分析还是拼成果图,都有了标准中间产物。

因为方向框在GeoJSON里要表示成五点闭合多边形,比水平四点框麻烦,建议先把水平框方案跑顺,再考虑旋转框导出。不要一开始就追求精细,先把整条链路走通。我自己在这条路上吃过的最大亏就是检测出了框但交付不了——坐标换算出错、格式对不上,业务方根本没法用。后来养成的习惯是每批结果都先落到GeoJSON再可视化检查。希望这些经验能帮你少踩几个坑,早日把遥感目标检测跑出自己的可用结果。

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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询