rsai 2026.5.23__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,399 @@
1
+ Metadata-Version: 2.4
2
+ Name: rsai
3
+ Version: 2026.5.23
4
+ Summary: Add your description here
5
+ Requires-Python: >=3.10
6
+ Description-Content-Type: text/markdown
7
+ Requires-Dist: gdal==3.4.3
8
+ Requires-Dist: numpy<2.0.0,>=1.24.4
9
+ Requires-Dist: pyproj
10
+ Requires-Dist: rich
11
+ Requires-Dist: loguru
12
+ Requires-Dist: shapely
13
+ Requires-Dist: mercantile>=1.2.1
14
+ Requires-Dist: aiohttp>=3.13.3
15
+ Provides-Extra: cv2
16
+ Requires-Dist: opencv-python; extra == "cv2"
17
+ Provides-Extra: pil
18
+ Requires-Dist: pillow; extra == "pil"
19
+ Provides-Extra: rasterio
20
+ Requires-Dist: rasterio<=1.3.10; extra == "rasterio"
21
+ Provides-Extra: all
22
+ Requires-Dist: opencv-python; extra == "all"
23
+ Requires-Dist: pillow; extra == "all"
24
+ Requires-Dist: rasterio<=1.3.10; extra == "all"
25
+
26
+ # rsai
27
+
28
+ 遥感图像 I/O 工具库,支持多后端读写、OGC 地图服务访问、矢量数据处理及训练样本制作。
29
+
30
+ ## 安装
31
+
32
+ ```bash
33
+ pip install rsai
34
+
35
+ # 安装可选后端
36
+ pip install "rsai[cv2]" # OpenCV
37
+ pip install "rsai[pil]" # Pillow
38
+ pip install "rsai[rasterio]" # Rasterio
39
+ pip install "rsai[all]" # 全部
40
+ ```
41
+
42
+ > 核心依赖:GDAL 3.4.3、NumPy、pyproj、Shapely、mercantile、aiohttp
43
+
44
+ ---
45
+
46
+ ## 快速开始
47
+
48
+ ### 读写本地图像
49
+
50
+ ```python
51
+ from rsio import open_image
52
+
53
+ # 读取(默认 GDAL 后端)
54
+ with open_image("image.tif") as img:
55
+ array = img.read() # 读取全图为 numpy 数组
56
+ print(img.width, img.height) # 图像尺寸
57
+ print(img.channel) # 波段数
58
+ print(img.dtype) # 数据类型
59
+ print(img.geo_transform) # 地理变换参数
60
+ print(img.geo_projection) # 投影信息(WKT)
61
+ print(img.geo_bounds) # 地理范围 (left, top, right, bottom)
62
+ print(img.pixel_size) # 像元大小 (x, y)
63
+ print(img.nodata) # 无效值
64
+
65
+ # 指定后端
66
+ with open_image("image.tif", backend="rasterio") as img:
67
+ array = img.read()
68
+
69
+ # 写入(需传入地理信息)
70
+ OpenImage.write_array(
71
+ "output.tif",
72
+ array,
73
+ backend="gdal",
74
+ geo_transform=geo_transform,
75
+ geo_projection=projection,
76
+ )
77
+ ```
78
+
79
+ ### 滑窗切片
80
+
81
+ ```python
82
+ with open_image("large.tif") as img:
83
+ # 生成器,逐块读取,节省内存
84
+ for tile_array, (x, y) in img.sliding_window_tiles(
85
+ window_size=512, # 也可传 (width, height)
86
+ stride=256, # 步长,默认等于 window_size(无重叠)
87
+ max_tiles=100, # 限制最大切片数
88
+ band_indexes=[1, 2, 3], # 指定波段
89
+ ):
90
+ pass
91
+
92
+ # 预估切片总数
93
+ total = img.count_tiles(stride=256)
94
+ ```
95
+
96
+ ### 均匀分块
97
+
98
+ ```python
99
+ with open_image("large.tif") as img:
100
+ # 自动计算最优行列数,使每块尽量接近正方形
101
+ for block_img, (x, y) in img.image_blocks(num_blocks=16):
102
+ array = block_img.read()
103
+ ```
104
+
105
+ ### 图像裁剪
106
+
107
+ ```python
108
+ with open_image("image.tif") as img:
109
+ # 按像素坐标裁剪
110
+ img.crop(x_off=100, y_off=100, window_x_size=512, window_y_size=512)
111
+
112
+ # 按地理范围裁剪(left, top, right, bottom)
113
+ img.crop_by_geo_bounds((116.3, 40.1, 116.5, 39.9))
114
+
115
+ # 按 GeoJSON 裁剪(需 rasterio 后端)
116
+ with open_image("image.tif", backend="rasterio") as img:
117
+ img.crop_by_geojson(geojson_dict_or_path)
118
+ ```
119
+
120
+ ### 重投影
121
+
122
+ ```python
123
+ with open_image("image.tif") as img:
124
+ # 支持 EPSG 整数、"EPSG:xxxx" 字符串、WKT 字符串、或另一个 OpenImage 对象
125
+ img.reproject(4326)
126
+ img.reproject("EPSG:32650")
127
+ img.reproject(other_img)
128
+ ```
129
+
130
+ ### 多图像求交集
131
+
132
+ ```python
133
+ from rsio import open_image
134
+ from rsio.open_image import OpenImage
135
+
136
+ img_a = open_image("a.tif")
137
+ img_b = open_image("b.tif")
138
+
139
+ # 自动对齐投影并裁剪到公共地理范围
140
+ img_a, img_b = OpenImage.intersection_image([img_a, img_b])
141
+ ```
142
+
143
+ ### 图像 resize
144
+
145
+ ```python
146
+ from rsio.open_image import OpenImage
147
+ import numpy as np
148
+
149
+ array = ... # (H, W, C) 或 (C, H, W)
150
+
151
+ # 直接 resize
152
+ resized = OpenImage.resize_img(array, target_size=(512, 512))
153
+
154
+ # 保持宽高比并 padding
155
+ resized = OpenImage.resize_img(
156
+ array,
157
+ target_size=512,
158
+ keep_ratio=True,
159
+ pad=0, # padding 填充值
160
+ resample=1, # 0=最近邻 1=双线性 2=双三次 3=区域 4=Lanczos
161
+ )
162
+ ```
163
+
164
+ ### 有效值掩码
165
+
166
+ ```python
167
+ from rsio.open_image import OpenImage
168
+
169
+ # 多通道不全为 0 且不全为 255 的像素为有效
170
+ mask = OpenImage.valid_mask_of_image(array) # shape: (H, W),bool
171
+ ```
172
+
173
+ ---
174
+
175
+ ## OGC 地图服务
176
+
177
+ ### 通用接口
178
+
179
+ ```python
180
+ from rsio import open_ogc
181
+
182
+ # XYZ 切片服务
183
+ with open_ogc("https://tile.openstreetmap.org/{z}/{x}/{y}.png", service="xyz") as ogc:
184
+ array = ogc.read(bbox=[116.3, 39.9, 116.5, 40.1], zoom=14)
185
+
186
+ # WMTS 服务
187
+ with open_ogc(url, service="wmts", layer="layer_name") as ogc:
188
+ array = ogc.read(bbox=..., zoom=14)
189
+
190
+ # WMS 服务
191
+ with open_ogc(url, service="wms", layer="layer_name") as ogc:
192
+ array = ogc.read(bbox=..., width=512, height=512)
193
+ ```
194
+
195
+ ### 预置地图服务
196
+
197
+ ```python
198
+ from rsio import open_ogc_service
199
+
200
+ # 天地图矢量底图(需申请 token)
201
+ with open_ogc_service("tianditu_vector", token="your_token") as svc:
202
+ image_array = svc.image.read(bbox=..., zoom=14)
203
+ label_array = svc.label.read(bbox=..., zoom=14) # 标注图层
204
+ shp = svc.shp # 矢量数据
205
+
206
+ # ESRI 影像
207
+ with open_ogc_service("esri_image") as svc:
208
+ array = svc.image.read(bbox=..., zoom=16)
209
+
210
+ # Google 影像
211
+ with open_ogc_service("google_image") as svc:
212
+ array = svc.image.read(bbox=..., zoom=16)
213
+
214
+ # CartoDB 矢量底图
215
+ with open_ogc_service("cartodb_vector") as svc:
216
+ array = svc.image.read(bbox=..., zoom=14)
217
+ ```
218
+
219
+ | 服务名 | 说明 | 需要 token |
220
+ |--------|------|-----------|
221
+ | `tianditu_vector` | 天地图矢量底图 + 标注 | 是 |
222
+ | `cartodb_vector` | CartoDB 矢量底图 | 否 |
223
+ | `esri_image` | ESRI 卫星影像 | 否 |
224
+ | `google_image` | Google 卫星影像 | 否 |
225
+
226
+ ---
227
+
228
+ ## Shapefile 操作
229
+
230
+ ```python
231
+ from rsio import open_shp
232
+
233
+ # 读取属性
234
+ with open_shp("data.shp") as shp:
235
+ print(shp.feature_count) # 要素数量
236
+ print(shp.extent) # 范围 (min_x, min_y, max_x, max_y)
237
+ print(shp.geo_bounds) # 地理范围
238
+ print(shp.geo_projection) # 投影信息
239
+ for feat in shp.features:
240
+ geom = feat.GetGeometryRef()
241
+
242
+ # 重投影并保存
243
+ with open_shp("data.shp") as shp:
244
+ shp.reproject(target_epsg=4326)
245
+ shp.save("reprojected.shp")
246
+
247
+ # 合并另一个 shp
248
+ with open_shp("base.shp") as shp:
249
+ shp.add_other_shp("extra.shp")
250
+ shp.save("merged.shp")
251
+
252
+ # 简化几何
253
+ with open_shp("data.shp") as shp:
254
+ shp.simplify_shp(tolerance=0.001)
255
+ shp.save("simplified.shp")
256
+
257
+ # 转为栅格图像(以参考图像的范围和分辨率为准)
258
+ with open_shp("data.shp") as shp:
259
+ img = shp.convert_to_open_image(ref_image="ref.tif")
260
+ img.save("rasterized.tif")
261
+ ```
262
+
263
+ ---
264
+
265
+ ## 训练样本制作
266
+
267
+ ### 语义分割样本
268
+
269
+ ```python
270
+ from rsio.build_samples import SemanticSampleBuilder
271
+
272
+ builder = SemanticSampleBuilder(
273
+ input_images="images/", # 图像目录或路径列表
274
+ input_labels="labels/", # 标签目录或路径列表(支持 tif/shp)
275
+ output_dir="samples/", # 输出目录
276
+ window_size=512, # 切片大小,也可传 (w, h)
277
+ stride=256, # 步长,默认等于 window_size
278
+ max_samples=None, # 最大样本数,None 表示不限
279
+ band_indexes=[1, 2, 3], # 指定波段,None 表示全部
280
+ palette=None, # 颜色映射表(用于彩色标签)
281
+ split_val_ratio=0.1, # 验证集比例
282
+ split_test_ratio=0.1, # 测试集比例
283
+ save_blank_sample_prob=0.05, # 保存全背景样本的概率(0 表示不保存)
284
+ input_mode=0, # 0: 路径列表 1: 目录按文件名匹配 2: 目录按地理范围匹配
285
+ num_workers=4, # 并行进程数
286
+ attribute_field="class_id", # shp 标签的属性字段名
287
+ mapping_field={"road": 1}, # shp 属性值到类别 id 的映射
288
+ image_prefix=None, # 图像文件名前缀过滤
289
+ label_suffix=None, # 标签文件名后缀过滤
290
+ crop=False, # 是否裁剪图像到标签范围
291
+ log_file="build.log", # 日志文件路径
292
+ )
293
+ builder.build()
294
+
295
+ # 生成可视化标签(将类别 id 映射为颜色)
296
+ builder.batch_build_color_label(
297
+ input_labels="labels/",
298
+ output_dir="color_labels/",
299
+ palette={0: (0,0,0), 1: (255,0,0)},
300
+ )
301
+
302
+ # 生成叠加可视化图(图像 + 标签半透明叠加)
303
+ builder.batch_build_visualizer_label(
304
+ input_images="images/",
305
+ input_labels="labels/",
306
+ output_dir="visualize/",
307
+ )
308
+ ```
309
+
310
+ 输出目录结构:
311
+
312
+ ```
313
+ samples/
314
+ ├── train/
315
+ │ ├── images/
316
+ │ └── labels/
317
+ ├── val/
318
+ │ ├── images/
319
+ │ └── labels/
320
+ └── test/
321
+ ├── images/
322
+ └── labels/
323
+ ```
324
+
325
+ ### 变化检测样本
326
+
327
+ ```python
328
+ from rsio.build_samples import ChangedSampleBuilder
329
+
330
+ builder = ChangedSampleBuilder(
331
+ input_images_a="time_a/", # 时相 A 图像目录
332
+ input_images_b="time_b/", # 时相 B 图像目录
333
+ input_labels="labels/", # 变化标签目录
334
+ output_dir="samples/",
335
+ window_size=512,
336
+ stride=256,
337
+ split_val_ratio=0.1,
338
+ split_test_ratio=0.1,
339
+ num_workers=4,
340
+ )
341
+ builder.build()
342
+ ```
343
+
344
+ 输出目录结构:
345
+
346
+ ```
347
+ samples/
348
+ ├── train/
349
+ │ ├── images_a/
350
+ │ ├── images_b/
351
+ │ └── labels/
352
+ ├── val/
353
+ │ ├── images_a/
354
+ │ ├── images_b/
355
+ │ └── labels/
356
+ └── test/
357
+ ├── images_a/
358
+ ├── images_b/
359
+ └── labels/
360
+ ```
361
+
362
+ ---
363
+
364
+ ## 后端说明
365
+
366
+ | 后端 | 关键字 | 适用场景 |
367
+ |------|--------|---------|
368
+ | GDAL(默认) | `gdal` | 地理栅格数据,支持完整地理信息,推荐首选 |
369
+ | Rasterio | `rasterio` | 地理栅格数据,支持 GeoJSON 裁剪 |
370
+ | PIL | `pil` | 普通图像,轻量读写,不含地理信息 |
371
+ | OpenCV | `cv2` | 图像处理,BGR 格式,resize/显示 |
372
+
373
+ 后端通过 `backend=` 参数指定,所有后端均实现相同的抽象接口(`ImageBackend`),可无缝切换。
374
+
375
+ ---
376
+
377
+ ## 项目结构
378
+
379
+ ```
380
+ rsio/
381
+ ├── open_image.py # 本地图像 I/O(OpenImage)
382
+ ├── open_ogc.py # OGC 服务(WMS/WMTS/XYZ)
383
+ ├── open_ogc_services.py # 预置地图服务
384
+ ├── open_shp.py # Shapefile I/O
385
+ ├── build_samples.py # 训练样本制作
386
+ ├── enums.py # 枚举定义
387
+ ├── backends/
388
+ │ ├── base_backend.py # 抽象基类 ImageBackend
389
+ │ ├── gdal_backend.py # GDALImage
390
+ │ ├── rasterio_backend.py # RasterioImage
391
+ │ ├── pil_backend.py # PILImage
392
+ │ └── cv2_backend.py # OpencvImage
393
+ └── utils/
394
+ ├── converters.py # 坐标/数组/颜色/BBox 转换
395
+ ├── decorators.py # 通用装饰器(类型检查、依赖检查等)
396
+ ├── exceptions.py # 统一异常体系
397
+ ├── geo.py # 栅格/矢量地理操作
398
+ └── misc.py # 日志、安全导入、列表工具
399
+ ```