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