fix(tools): fix and update some (#110)
* refactor(tools): update savegeotiff and timer * fix(geojson2mask): add convert tiff to EPSG:4326 * fix(geojson2mask): fix use tiff's EPSG * fix(mask2geojson): update hole and fix srs * fix(tools): update merge raster2vector * feat(tools): update spliter to support HSI * fix(raster2vector): fix save geojson without ignore index * fix(tools): name fixedown
parent
3af03678d4
commit
ec9d58bb0a
14 changed files with 276 additions and 271 deletions
@ -1,81 +0,0 @@ |
|||||||
# Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved. |
|
||||||
# |
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License"); |
|
||||||
# you may not use this file except in compliance with the License. |
|
||||||
# You may obtain a copy of the License at |
|
||||||
# |
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0 |
|
||||||
# |
|
||||||
# Unless required by applicable law or agreed to in writing, software |
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS, |
|
||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||||
# See the License for the specific language governing permissions and |
|
||||||
# limitations under the License. |
|
||||||
|
|
||||||
import codecs |
|
||||||
import argparse |
|
||||||
|
|
||||||
import cv2 |
|
||||||
import numpy as np |
|
||||||
import geojson |
|
||||||
from geojson import Polygon, Feature, FeatureCollection |
|
||||||
|
|
||||||
from utils import Raster, Timer |
|
||||||
|
|
||||||
|
|
||||||
def _gt_convert(x, y, geotf): |
|
||||||
x_geo = geotf[0] + x * geotf[1] + y * geotf[2] |
|
||||||
y_geo = geotf[3] + x * geotf[4] + y * geotf[5] |
|
||||||
return x_geo, y_geo |
|
||||||
|
|
||||||
|
|
||||||
@Timer |
|
||||||
def convert_data(mask_path, save_path, epsilon=0): |
|
||||||
raster = Raster(mask_path) |
|
||||||
img = raster.getArray() |
|
||||||
ext = save_path.split(".")[-1] |
|
||||||
if ext != "json" and ext != "geojson": |
|
||||||
raise ValueError("The ext of `save_path` must be `json` or `geojson`, not {}.".format(ext)) |
|
||||||
geo_writer = codecs.open(save_path, "w", encoding="utf-8") |
|
||||||
clas = np.unique(img) |
|
||||||
cv2_v = (cv2.__version__.split(".")[0] == "3") |
|
||||||
feats = [] |
|
||||||
if not isinstance(epsilon, (int, float)): |
|
||||||
epsilon = 0 |
|
||||||
for iclas in range(1, len(clas)): |
|
||||||
tmp = np.zeros_like(img).astype("uint8") |
|
||||||
tmp[img == iclas] = 1 |
|
||||||
# TODO: Detect internal and external contour |
|
||||||
results = cv2.findContours(tmp, cv2.RETR_EXTERNAL, |
|
||||||
cv2.CHAIN_APPROX_TC89_KCOS) |
|
||||||
contours = results[1] if cv2_v else results[0] |
|
||||||
# hierarchys = results[2] if cv2_v else results[1] |
|
||||||
if len(contours) == 0: |
|
||||||
continue |
|
||||||
for contour in contours: |
|
||||||
contour = cv2.approxPolyDP(contour, epsilon, True) |
|
||||||
polys = [] |
|
||||||
for point in contour: |
|
||||||
x, y = point[0] |
|
||||||
xg, yg = _gt_convert(x, y, raster.geot) |
|
||||||
polys.append((xg, yg)) |
|
||||||
polys.append(polys[0]) |
|
||||||
feat = Feature( |
|
||||||
geometry=Polygon([polys]), properties={"class": int(iclas)}) |
|
||||||
feats.append(feat) |
|
||||||
gjs = FeatureCollection(feats) |
|
||||||
geo_writer.write(geojson.dumps(gjs)) |
|
||||||
geo_writer.close() |
|
||||||
|
|
||||||
|
|
||||||
parser = argparse.ArgumentParser(description="input parameters") |
|
||||||
parser.add_argument("--mask_path", type=str, required=True, \ |
|
||||||
help="The path of mask tif.") |
|
||||||
parser.add_argument("--save_path", type=str, required=True, \ |
|
||||||
help="The path to save the results, file suffix is `*.json/geojson`.") |
|
||||||
parser.add_argument("--epsilon", type=float, default=0, \ |
|
||||||
help="The CV2 simplified parameters, `0` is the default.") |
|
||||||
|
|
||||||
if __name__ == "__main__": |
|
||||||
args = parser.parse_args() |
|
||||||
convert_data(args.mask_path, args.save_path, args.epsilon) |
|
@ -1,93 +0,0 @@ |
|||||||
# Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved. |
|
||||||
# |
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License"); |
|
||||||
# you may not use this file except in compliance with the License. |
|
||||||
# You may obtain a copy of the License at |
|
||||||
# |
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0 |
|
||||||
# |
|
||||||
# Unless required by applicable law or agreed to in writing, software |
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS, |
|
||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||||
# See the License for the specific language governing permissions and |
|
||||||
# limitations under the License. |
|
||||||
|
|
||||||
import os |
|
||||||
import os.path as osp |
|
||||||
import argparse |
|
||||||
|
|
||||||
import numpy as np |
|
||||||
from PIL import Image |
|
||||||
try: |
|
||||||
from osgeo import gdal, ogr, osr |
|
||||||
except ImportError: |
|
||||||
import gdal |
|
||||||
import ogr |
|
||||||
import osr |
|
||||||
|
|
||||||
from utils import Raster, Timer |
|
||||||
|
|
||||||
|
|
||||||
def _mask2tif(mask_path, tmp_path, proj, geot): |
|
||||||
mask = np.asarray(Image.open(mask_path)) |
|
||||||
if len(mask.shape) == 3: |
|
||||||
mask = mask[:, :, 0] |
|
||||||
row, columns = mask.shape[:2] |
|
||||||
driver = gdal.GetDriverByName("GTiff") |
|
||||||
dst_ds = driver.Create(tmp_path, columns, row, 1, gdal.GDT_UInt16) |
|
||||||
dst_ds.SetGeoTransform(geot) |
|
||||||
dst_ds.SetProjection(proj) |
|
||||||
dst_ds.GetRasterBand(1).WriteArray(mask) |
|
||||||
dst_ds.FlushCache() |
|
||||||
return dst_ds |
|
||||||
|
|
||||||
|
|
||||||
def _polygonize_raster(mask_path, shp_save_path, proj, geot, ignore_index): |
|
||||||
tmp_path = shp_save_path.replace(".shp", ".tif") |
|
||||||
ds = _mask2tif(mask_path, tmp_path, proj, geot) |
|
||||||
srcband = ds.GetRasterBand(1) |
|
||||||
maskband = srcband.GetMaskBand() |
|
||||||
gdal.SetConfigOption("GDAL_FILENAME_IS_UTF8", "YES") |
|
||||||
gdal.SetConfigOption("SHAPE_ENCODING", "UTF-8") |
|
||||||
ogr.RegisterAll() |
|
||||||
drv = ogr.GetDriverByName("ESRI Shapefile") |
|
||||||
if osp.exists(shp_save_path): |
|
||||||
os.remove(shp_save_path) |
|
||||||
dst_ds = drv.CreateDataSource(shp_save_path) |
|
||||||
prosrs = osr.SpatialReference(wkt=ds.GetProjection()) |
|
||||||
dst_layer = dst_ds.CreateLayer( |
|
||||||
"Building boundary", geom_type=ogr.wkbPolygon, srs=prosrs) |
|
||||||
dst_fieldname = "DN" |
|
||||||
fd = ogr.FieldDefn(dst_fieldname, ogr.OFTInteger) |
|
||||||
dst_layer.CreateField(fd) |
|
||||||
gdal.Polygonize(srcband, maskband, dst_layer, 0, []) |
|
||||||
lyr = dst_ds.GetLayer() |
|
||||||
lyr.SetAttributeFilter("DN = '{}'".format(str(ignore_index))) |
|
||||||
for holes in lyr: |
|
||||||
lyr.DeleteFeature(holes.GetFID()) |
|
||||||
dst_ds.Destroy() |
|
||||||
ds = None |
|
||||||
os.remove(tmp_path) |
|
||||||
|
|
||||||
|
|
||||||
@Timer |
|
||||||
def raster2shp(srcimg_path, mask_path, save_path, ignore_index=255): |
|
||||||
src = Raster(srcimg_path) |
|
||||||
_polygonize_raster(mask_path, save_path, src.proj, src.geot, ignore_index) |
|
||||||
src = None |
|
||||||
|
|
||||||
|
|
||||||
parser = argparse.ArgumentParser(description="input parameters") |
|
||||||
parser.add_argument("--srcimg_path", type=str, required=True, \ |
|
||||||
help="The path of original data with geoinfos.") |
|
||||||
parser.add_argument("--mask_path", type=str, required=True, \ |
|
||||||
help="The path of mask data.") |
|
||||||
parser.add_argument("--save_path", type=str, default="output", \ |
|
||||||
help="The path to save the results shapefile, `output` is the default.") |
|
||||||
parser.add_argument("--ignore_index", type=int, default=255, \ |
|
||||||
help="It will not be converted to the value of SHP, `255` is the default.") |
|
||||||
|
|
||||||
if __name__ == "__main__": |
|
||||||
args = parser.parse_args() |
|
||||||
raster2shp(args.srcimg_path, args.mask_path, args.save_path, |
|
||||||
args.ignore_index) |
|
@ -0,0 +1,102 @@ |
|||||||
|
# Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved. |
||||||
|
# |
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
# you may not use this file except in compliance with the License. |
||||||
|
# You may obtain a copy of the License at |
||||||
|
# |
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0 |
||||||
|
# |
||||||
|
# Unless required by applicable law or agreed to in writing, software |
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
# See the License for the specific language governing permissions and |
||||||
|
# limitations under the License. |
||||||
|
|
||||||
|
import os |
||||||
|
import os.path as osp |
||||||
|
import argparse |
||||||
|
|
||||||
|
import numpy as np |
||||||
|
from PIL import Image |
||||||
|
try: |
||||||
|
from osgeo import gdal, ogr, osr |
||||||
|
except ImportError: |
||||||
|
import gdal |
||||||
|
import ogr |
||||||
|
import osr |
||||||
|
|
||||||
|
from utils import Raster, save_geotiff, timer |
||||||
|
|
||||||
|
|
||||||
|
def _mask2tif(mask_path, tmp_path, proj, geot): |
||||||
|
dst_ds = save_geotiff( |
||||||
|
np.asarray(Image.open(mask_path)), |
||||||
|
tmp_path, proj, geot, gdal.GDT_UInt16, False) |
||||||
|
return dst_ds |
||||||
|
|
||||||
|
|
||||||
|
def _polygonize_raster(mask_path, vec_save_path, proj, geot, ignore_index, ext): |
||||||
|
if proj is None or geot is None: |
||||||
|
tmp_path = None |
||||||
|
ds = gdal.Open(mask_path) |
||||||
|
else: |
||||||
|
tmp_path = vec_save_path.replace("." + ext, ".tif") |
||||||
|
ds = _mask2tif(mask_path, tmp_path, proj, geot) |
||||||
|
srcband = ds.GetRasterBand(1) |
||||||
|
maskband = srcband.GetMaskBand() |
||||||
|
gdal.SetConfigOption("GDAL_FILENAME_IS_UTF8", "YES") |
||||||
|
gdal.SetConfigOption("SHAPE_ENCODING", "UTF-8") |
||||||
|
ogr.RegisterAll() |
||||||
|
drv = ogr.GetDriverByName( |
||||||
|
"ESRI Shapefile" if ext == "shp" else "GeoJSON" |
||||||
|
) |
||||||
|
if osp.exists(vec_save_path): |
||||||
|
os.remove(vec_save_path) |
||||||
|
dst_ds = drv.CreateDataSource(vec_save_path) |
||||||
|
prosrs = osr.SpatialReference(wkt=ds.GetProjection()) |
||||||
|
dst_layer = dst_ds.CreateLayer( |
||||||
|
"POLYGON", geom_type=ogr.wkbPolygon, srs=prosrs) |
||||||
|
dst_fieldname = "CLAS" |
||||||
|
fd = ogr.FieldDefn(dst_fieldname, ogr.OFTInteger) |
||||||
|
dst_layer.CreateField(fd) |
||||||
|
gdal.Polygonize(srcband, maskband, dst_layer, 0, []) |
||||||
|
# TODO: temporary: delete ignored values |
||||||
|
dst_ds.Destroy() |
||||||
|
ds = None |
||||||
|
vec_ds = drv.Open(vec_save_path, 1) |
||||||
|
lyr = vec_ds.GetLayer() |
||||||
|
lyr.SetAttributeFilter("{} = '{}'".format(dst_fieldname, str(ignore_index))) |
||||||
|
for holes in lyr: |
||||||
|
lyr.DeleteFeature(holes.GetFID()) |
||||||
|
vec_ds.Destroy() |
||||||
|
if tmp_path is not None: |
||||||
|
os.remove(tmp_path) |
||||||
|
|
||||||
|
|
||||||
|
@timer |
||||||
|
def raster2vector(srcimg_path, mask_path, save_path, ignore_index=255): |
||||||
|
vec_ext = save_path.split(".")[-1].lower() |
||||||
|
if vec_ext not in ["json", "geojson", "shp"]: |
||||||
|
raise ValueError("The ext of `save_path` must be `json/geojson` or `shp`, not {}.".format(vec_ext)) |
||||||
|
ras_ext = srcimg_path.split(".")[-1].lower() |
||||||
|
if osp.exists(srcimg_path) and ras_ext in ["tif", "tiff", "geotiff", "img"]: |
||||||
|
src = Raster(srcimg_path) |
||||||
|
_polygonize_raster(mask_path, save_path, src.proj, src.geot, ignore_index, vec_ext) |
||||||
|
src = None |
||||||
|
else: |
||||||
|
_polygonize_raster(mask_path, save_path, None, None, ignore_index, vec_ext) |
||||||
|
|
||||||
|
|
||||||
|
parser = argparse.ArgumentParser(description="input parameters") |
||||||
|
parser.add_argument("--mask_path", type=str, required=True, \ |
||||||
|
help="The path of mask data.") |
||||||
|
parser.add_argument("--save_path", type=str, required=True, \ |
||||||
|
help="The path to save the results, file suffix is `*.json/geojson` or `*.shp`.") |
||||||
|
parser.add_argument("--srcimg_path", type=str, default="", \ |
||||||
|
help="The path of original data with geoinfos, `` is the default.") |
||||||
|
parser.add_argument("--ignore_index", type=int, default=255, \ |
||||||
|
help="It will not be converted to the value of SHP, `255` is the default.") |
||||||
|
|
||||||
|
if __name__ == "__main__": |
||||||
|
args = parser.parse_args() |
||||||
|
raster2vector(args.srcimg_path, args.mask_path, args.save_path, args.ignore_index) |
@ -0,0 +1,53 @@ |
|||||||
|
# Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved. |
||||||
|
# |
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
# you may not use this file except in compliance with the License. |
||||||
|
# You may obtain a copy of the License at |
||||||
|
# |
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0 |
||||||
|
# |
||||||
|
# Unless required by applicable law or agreed to in writing, software |
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
# See the License for the specific language governing permissions and |
||||||
|
# limitations under the License. |
||||||
|
|
||||||
|
# reference: https://zhuanlan.zhihu.com/p/378918221 |
||||||
|
|
||||||
|
try: |
||||||
|
from osgeo import gdal, ogr, osr |
||||||
|
except: |
||||||
|
import gdal |
||||||
|
import ogr |
||||||
|
import osr |
||||||
|
|
||||||
|
|
||||||
|
def vector_translate(geojson_path: str, |
||||||
|
wo_wkt: str, |
||||||
|
g_type: str="POLYGON", |
||||||
|
dim: str="XY") -> str: |
||||||
|
ogr.RegisterAll() |
||||||
|
gdal.SetConfigOption("GDAL_FILENAME_IS_UTF8", "YES") |
||||||
|
data = ogr.Open(geojson_path) |
||||||
|
layer = data.GetLayer() |
||||||
|
spatial = layer.GetSpatialRef() |
||||||
|
layerName = layer.GetName() |
||||||
|
data.Destroy() |
||||||
|
dstSRS = osr.SpatialReference() |
||||||
|
dstSRS.ImportFromWkt(wo_wkt) |
||||||
|
ext = "." + geojson_path.split(".")[-1] |
||||||
|
save_path = geojson_path.replace(ext, ("_tmp" + ext)) |
||||||
|
options = gdal.VectorTranslateOptions( |
||||||
|
srcSRS=spatial, |
||||||
|
dstSRS=dstSRS, |
||||||
|
reproject=True, |
||||||
|
layerName=layerName, |
||||||
|
geometryType=g_type, |
||||||
|
dim=dim |
||||||
|
) |
||||||
|
gdal.VectorTranslate( |
||||||
|
save_path, |
||||||
|
srcDS=geojson_path, |
||||||
|
options=options |
||||||
|
) |
||||||
|
return save_path |
Loading…
Reference in new issue