按 ROI 裁剪 DOM/DSM/PCD¶
Using region of interest (ROI, e.g. plot boundary), cropping each of them from large digital orthomosaic (DOM), digital surface model (DSM), and point cloud of whole field, without using any GIS or point cloud processing software.

包和数据准备。¶
导入 easyidp 包并使用示例的最简单方法是:
[1]:
import easyidp as idp
lotus = idp.data.Lotus()
如果您是第一次运行,它将自动从 Google Drive 下载 3.3GB 的数据集,请参考 Data 了解更多详情。
从 Shapefile 读取 ROI¶
以下代码将加载并打开 Lotus 数据集中的地块边界 shapefile,shp 文件看起来像这样(红色多边形):

[2]:
roi = idp.ROI(lotus.shp, name_field='plot_id')
[shp][proj] Use projection [WGS 84] for loaded shapefile [plots.shp]
Read shapefile [plots.shp]: 100%|██████████| 112/112 [00:00<00:00, 2347.62it/s]
[3]:
roi
[3]:
<easyidp.ROI> with 112 items
[0] N1W1
array([[139.54052962, 35.73475194],
[139.54055106, 35.73475596],
[139.54055592, 35.73473843],
[139.54053438, 35.73473446],
[139.54052962, 35.73475194]])
[1] N1W2
array([[139.54053488, 35.73473289],
[139.54055632, 35.73473691],
[139.54056118, 35.73471937],
[139.54053963, 35.73471541],
[139.54053488, 35.73473289]])
...
[110] S4E6
array([[139.54090456, 35.73453742],
[139.540926 , 35.73454144],
[139.54093086, 35.7345239 ],
[139.54090932, 35.73451994],
[139.54090456, 35.73453742]])
[111] S4E7
array([[139.54090986, 35.73451856],
[139.54093129, 35.73452258],
[139.54093616, 35.73450504],
[139.54091461, 35.73450107],
[139.54090986, 35.73451856]])
另见
有关加载 shapefile 时参数的更多详细信息,请参考 从 shapefile 加载 ROI,或 python API easyidp.ROI,和 easyidp.shp.read_shp。
读取和裁剪 geotiff (DOM/DSM)¶
首先,通过以下方式打开 DOM geotiff 文件:
[4]:
lotus.metashape.dom
[4]:
PosixPath('/Users/hwang/Library/Application Support/easyidp.data/2017_tanashi_lotus/170531.Lotus.outputs/170531.Lotus_dom.tif')
[5]:
dom = idp.GeoTiff(lotus.metashape.dom)
另见
GeoTiff 是 easyidp 定义的类,包含几个必需的信息。请查看 python API easyidp.GeoTiff 了解更多信息
然而,在这种情况下,ROI 和 GeoTiff 不共享相同的地理坐标:
[6]:
print("ROI.CRS: ", roi.crs.name, "\nDOM.CRS: ", dom.crs.name)
ROI.CRS: WGS 84
DOM.CRS: WGS 84 / UTM zone 54N
因此需要将 ROI 转换为与 GeoTiff 相同的 CRS,更多详细信息请参考 从 shapefile 加载 ROI
[7]:
roi.change_crs(dom.crs)
然后使用以下函数从整个区域 GeoTIff 中裁剪每个 ROI(图):
[8]:
dom_parts = roi.crop(dom)
Crop roi from geotiff [170531.Lotus_dom.tif]: 100%|██████████| 112/112 [00:03<00:00, 30.07it/s]
输出的 dom_parts 是一个字典,使用地块标签作为键,裁剪的 imarray 作为值:
[9]:
import matplotlib.pyplot as plt
[10]:
plt.imshow(dom_parts['N1W1'])
[10]:
<matplotlib.image.AxesImage at 0x7fbf288812e0>
如果您想保存裁剪的 GeoTiff,请在裁剪时传递 save_folder 参数
>>> dom_parts = roi.crop(dom, save_folder=r"expected\save\folder")
它会将所有裁剪的部分保存到带有地理偏移的 GeoTiff 文件中(您可以几乎完美地将裁剪的 DOM 与原始 DOM 重叠)
未来工作
目前不能仅将单个输出 dom_parts["N1W1"] 保存为具有正确地理位置的标准 GeoTiff 文件,而无需之前的 save_folder 批量保存,但未来将支持通过 dom_part["N1W1"].save("path\to\save\N1W1.tif") 直接保存此类文件
裁剪 DSM 的步骤与 DOM 相同,这里忽略。
读取和裁剪点云¶
点云也使用与 GeoTiff 相同的过程
另见
PointCloud 是 easyidp 定义的类,包含几个必需的信息。请查看 python API easyidp.PointCloud 了解更多信息
[11]:
pcd = idp.PointCloud(lotus.metashape.pcd)
检查点云值:
[12]:
pcd
[12]:
x y z r g b nx ny nz
0 368016.142 3955509.827 94.017 129 132 147 nodata nodata nodata
1 368016.142 3955509.827 94.017 129 132 147 nodata nodata nodata
2 368016.142 3955509.827 94.017 129 132 147 nodata nodata nodata
... ... ... ... ... ... ... ... ... ...
10158190 368056.169 3955481.725 97.425 174 163 149 nodata nodata nodata
10158191 368056.51 3955481.904 97.44 166 153 139 nodata nodata nodata
10158192 368056.538 3955481.486 97.447 97 112 72 nodata nodata nodata
并裁剪:
注意
请确保 ROI 和点云之间的 CRS 相同。
[13]:
pcd_parts = roi.crop(pcd)
Crop roi from point cloud [170531.Lotus.laz]: 100%|██████████| 112/112 [00:30<00:00, 3.61it/s]
输出的 pcd_parts 是一个字典,使用地块标签作为键,裁剪的点云作为值:
[14]:
pcd_parts["N1W1"]
[14]:
x y z r g b nx ny nz
0 368017.889 3955510.812 97.214 nodata nodata nodata nodata nodata nodata
1 368017.888 3955510.8 97.218 nodata nodata nodata nodata nodata nodata
2 368017.897 3955510.964 97.22 nodata nodata nodata nodata nodata nodata
... ... ... ... ... ... ... ... ... ...
35745 368020.003 3955509.546 97.558 nodata nodata nodata nodata nodata nodata
35746 368020.046 3955509.665 97.436 nodata nodata nodata nodata nodata nodata
35747 368019.914 3955509.974 97.444 nodata nodata nodata nodata nodata nodata
同样,您可以传递 save_folder 参数来保存裁剪的点云
>>> pcd_parts = roi.crop(pcd, save_folder=r"expected\save\folder")
或者您可以通过以下方式仅保存一个点云:
>>> pcd_part["N1W1"].save(r"path\to\save\N1W1.ply")