From 3a5692be8172854ceaf03bcb0f64110d6b8951c1 Mon Sep 17 00:00:00 2001 From: geoyee Date: Thu, 23 Dec 2021 16:00:34 +0800 Subject: [PATCH] Update add block save --- README.md | 12 +-- buildseg/buildSeg.py | 84 ++++++++++----------- buildseg/utils/__init__.py | 3 +- buildseg/utils/boundary.py | 147 ------------------------------------- buildseg/utils/convert.py | 2 +- buildseg/utils/shape.py | 13 +++- buildseg/utils/simplify.py | 5 +- buildseg/utils/splicing.py | 119 +++++++++++++++++++++--------- docs/README_CN.md | 15 ++-- 9 files changed, 150 insertions(+), 250 deletions(-) delete mode 100644 buildseg/utils/boundary.py diff --git a/README.md b/README.md index f4173a5..3e885bc 100644 --- a/README.md +++ b/README.md @@ -82,15 +82,15 @@ This work is in progress, at present, the relevant documents are as follows : - [x] Add note: - [x] About how to training your data in AI Studio / Local. - [x] About different model (paper's link). -- [ ] Accelerate: +- [x] Accelerate and reduce memory: - [x] PaddlePaddle setting. - [x] Add maximum pixelsize to calculate / using GDAL `translat / warp` to make raster smaller. - - [ ] Block stacking and saving. -- [ ] Add online map tiles support: - - [ ] Extract building on raster in memory. - - [ ] Add vector range selection. - + - [x] Block stacking and saving. - [ ] Test: - [x] On Windows 10/11. - [ ] On Linux. - [ ] On mac OS Big Sur+. + +- [ ] Add online map tiles support: + - [ ] Extract building on raster in memory. + - [ ] Add vector range selection. \ No newline at end of file diff --git a/buildseg/buildSeg.py b/buildseg/buildSeg.py index aee132e..ff5f0f1 100644 --- a/buildseg/buildSeg.py +++ b/buildseg/buildSeg.py @@ -204,6 +204,7 @@ def unload(self): action) self.iface.removeToolBarIcon(action) + # Load parameters def select_params_file(self): self.param_file = self.dlg.mQfwParams.filePath() @@ -216,9 +217,9 @@ def select_params_file(self): "use_bf16": self.dlg.ccbBF16.isChecked() } self.infer_worker.load_model(self.model_file, self.param_file, use_setting) - print("Parameters loaded successfully") + print("Parameters loaded successfully!") else: - print(f"Parameters loaded unsuccessfully, not find {self.model_file}") + print(f"Parameters loaded unsuccessfully, not find {self.model_file}.") # Select shapefile save path @@ -231,6 +232,7 @@ def simp_state_change(self, state): self.dlg.lblThreshold.setEnabled(bool(state // 2)) self.dlg.mQgsDoubleSpinBox.setEnabled(bool(state // 2)) + # chackbox state def gpu_state_change(self, state): if self.dlg.ccbGPU.isChecked(): @@ -265,13 +267,14 @@ def __display_error(info_txt): import numpy import paddle except ImportError: - __display_error("Please check if `numpy / opencv-python / paddlepaddle` exists in your environment!") + __display_error("Please check if `numpy / opencv-python / paddlepaddle` " + \ + "exists in your environment!") self.first_start = True return False # check paddlepaddle's version vers = paddle.__version__.split(".") if int(vers[0]) < 2 or int(vers[1]) < 2: - __display_error("Please make sure your paddlepaddle's version is greater than 2.2.0") + __display_error("Please make sure your paddlepaddle's version is greater than 2.2.0.") self.first_start = True return False # global import utils @@ -301,12 +304,12 @@ def init_setting(self): # # quick test in my computer # self.dlg.cbxScale.setCurrentIndex(5) # self.dlg.mQfwShape.setFilePath(r"C:\Users\Geoyee\Desktop\dd\test.shp") - # self.dlg.mQfwParams.setFilePath(r"E:\dataFiles\github\buildseg\static_weight\bisenet_v2_512x512\model.pdiparams") + # self.dlg.mQfwParams.setFilePath( + # r"E:\dataFiles\github\buildseg\static_weight\bisenet_v2_512x512\model.pdiparams") def run(self): """Run method that performs all the real work""" - # Create the dialog with elements (after translation) and keep reference # Only create GUI ONCE in callback, so that it will only load when the plugin is started if self.first_start == True: @@ -315,7 +318,7 @@ def run(self): self.init_setting() # init all of widget's settings # check env check_pass = self.check_python_pip_env() - if check_pass is True: + if check_pass is True: # env ok self.infer_worker = utils.InferWorker(self.model_file, self.param_file) # Run the dialog event loop result = self.dlg.exec_() @@ -323,69 +326,58 @@ def run(self): if result: # Start timing time_start = time.time() - # Do something useful here - delete the line containing pass and - # substitute with your code. # Get parameters grid_size = [int(self.dlg.cbxBlock.currentText())] * 2 overlap = [int(self.dlg.cbxOverlap.currentText())] * 2 scale_rate = float(self.dlg.cbxScale.currentText()) - print(f"grid_size is {grid_size}, overlap is {overlap}, scale_rate is {scale_rate}") + print(f"grid_size is {grid_size}, overlap is {overlap}, scale_rate is {scale_rate}.") # layers = iface.activeLayer() # Get the currently active layer - current_raster_layer = self.dlg.mMapLayerComboBoxR.currentLayer() # Get the selected raster layer - band_list = current_raster_layer.renderer().usesBands() # Band used by the current renderer - current_raster_layer_name = current_raster_layer.source() # Get the raster layer path + # Get the selected raster layer + current_raster_layer = self.dlg.mMapLayerComboBoxR.currentLayer() + # Band used by the current renderer + band_list = current_raster_layer.renderer().usesBands() + # Get the raster layer path + current_raster_layer_name = current_raster_layer.source() # Add downsample - layer_path = utils.dowm_sample(current_raster_layer_name, scale_rate) - # open raster to get tf and proj - # fn_ras = QgsProject.instance().mapLayersByName(current_raster_layer_name)[0] - # ras_path = str(fn_ras.dataProvider().dataSourceUri()) + down_save_path = self.save_shp_path.replace(".shp", "_dowm.tif") + layer_path = utils.dowm_sample(current_raster_layer_name, down_save_path, scale_rate) + print(f"layer_path: {layer_path}") ras_ds = gdal.Open(layer_path) geot = ras_ds.GetGeoTransform() proj = ras_ds.GetProjection() - # proj = layers.crs() # If this layer is a raster layer xsize = ras_ds.RasterXSize ysize = ras_ds.RasterYSize - grid_count, mask_grids = utils.create_grids(ysize, xsize, grid_size, overlap) + ras_ds = None + grid_count = utils.create_grids(ysize, xsize, grid_size, overlap) number = grid_count[0] * grid_count[1] # print(f"xsize is {xsize}, ysize is {ysize}, grid_count is {grid_count}") # test - print("Start block processing") + print("Start block processing.") + geoinfo = {"row": ysize, "col": xsize, "geot": geot, "proj": proj} + mask_save_path = self.save_shp_path.replace(".shp", "_mask.tif") + mask = utils.Mask(mask_save_path, geoinfo, grid_size, overlap) for i in range(grid_count[0]): for j in range(grid_count[1]): img = utils.layer2array(layer_path, band_list, i, j, grid_size, overlap) - # cv2.imwrite("C:/Users/Geoyee/Desktop/dd/" + str(i) + "-" + str(j) + ".jpg", img) # test - mask_grids[i][j] = self.infer_worker.infer(img, True) - # cv2.imwrite("C:/Users/Geoyee/Desktop/dd/" + str(i) + "-" + str(j) + ".png", mask_grids[i][j]) # test - print(f"-- {i * grid_count[1] + j + 1}/{number} --") - print("Start Spliting") - mask = utils.splicing_grids(mask_grids, ysize, xsize, grid_size, overlap) - # cv2.imwrite("C:/Users/Geoyee/Desktop/test.png", mask) # test - print("Start to extract the boundary") - # # raster to shapefile used OpenCV - # build_bound = bound2shp(get_polygon(mask), - # get_transform(layers)) - # vl = showgeoms([build_bound], "Building boundary", proj=proj) - # if self.save_shp_path is not None: - # QgsVectorFileWriter.writeAsVectorFormat( - # vl, self.save_shp_path, "utf-8", - # driverName="ESRI Shapefile") - # print(f"Save the Shapefile in {self.save_shp_path}") - # # raster to shapefile used GDAL + # mask_grids[i][j] = self.infer_worker.infer(img, True) + mask.write_grid(self.infer_worker.infer(img, True), i, j) + print(f"-- {i * grid_count[1] + j + 1}/{number} --.") + print("Start Spliting.") + # mask = utils.splicing_grids(mask_grids, ysize, xsize, grid_size, overlap) + print("Start to extract the boundary.") + # raster to shapefile used GDAL is_simp = self.dlg.ccbSimplify.isChecked() - utils.polygonize_raster(mask, self.save_shp_path, proj, geot, display=(not is_simp)) + utils.polygonize_raster(mask, self.save_shp_path, proj, geot, \ + display=(not is_simp)) if is_simp is True: - simp_save_path = osp.join(osp.dirname(self.save_shp_path), \ - osp.basename(self.save_shp_path).replace(".shp", "_simp.shp")) - utils.simplify_polygon(self.save_shp_path, \ - simp_save_path, \ + simp_save_path = self.save_shp_path.replace(".shp", "_simp.shp") + utils.simplify_polygon(self.save_shp_path, simp_save_path, \ self.dlg.mQgsDoubleSpinBox.value()) iface.addVectorLayer(simp_save_path, "deepbands-simplified", "ogr") - else : - print ('No') # # Reset model params # self.infer_worker.reset_model() time_end = time.time() iface.messageBar().pushMessage( - f"The whole operation is performed in less than {str(time_end - time_start)} seconds", + f"The whole operation is performed in {str(time_end - time_start)} seconds.", level=Qgis.Info, duration=30) diff --git a/buildseg/utils/__init__.py b/buildseg/utils/__init__.py index db88277..943ab19 100644 --- a/buildseg/utils/__init__.py +++ b/buildseg/utils/__init__.py @@ -1,7 +1,6 @@ from .infer import InferWorker from .qgser import showgeoms, get_transform, bound2shp from .convert import layer2array -from .splicing import create_grids, splicing_grids -from .boundary import get_polygon +from .splicing import create_grids, Mask # splicing_grids from .shape import polygonize_raster from .simplify import simplify_polygon, dowm_sample \ No newline at end of file diff --git a/buildseg/utils/boundary.py b/buildseg/utils/boundary.py deleted file mode 100644 index a5f0465..0000000 --- a/buildseg/utils/boundary.py +++ /dev/null @@ -1,147 +0,0 @@ -import cv2 -import numpy as np -import math - - -# TODO: 把挖孔不使用连接线重叠 -def get_polygon(label, sample="Dynamic"): - results = cv2.findContours( - image=label, mode=cv2.RETR_TREE, method=cv2.CHAIN_APPROX_TC89_KCOS - ) # 获取内外边界,用RETR_TREE更好表示 - cv2_v = cv2.__version__.split(".")[0] - contours = results[1] if cv2_v == "3" else results[0] # 边界 - hierarchys = results[2] if cv2_v == "3" else results[1] # 隶属信息 - if len(contours) != 0: # 可能出现没有边界的情况 - polygons = [] - relas = [] - for idx, (contour, hierarchy) in enumerate(zip(contours, hierarchys[0])): - # print(hierarchy) - # opencv实现边界简化 - epsilon = ( - 0.005 * cv2.arcLength(contour, True) if sample == "Dynamic" else sample - ) - if not isinstance(epsilon, float) and not isinstance(epsilon, int): - epsilon = 0 - # print("epsilon:", epsilon) - # -- Douglas-Peucker算法边界简化 - contour = cv2.approxPolyDP(contour, epsilon / 10, True) - # -- 自定义(角度和距离)边界简化 - out = approx_poly_DIY(contour) - # 给出关系 - rela = ( - idx, # own - hierarchy[-1] if hierarchy[-1] != -1 else None, - ) # parent - polygon = [] - for p in out: - polygon.append(p[0]) - polygons.append(polygon) # 边界 - relas.append(rela) # 关系 - for i in range(len(relas)): - if relas[i][1] != None: # 有父圈 - for j in range(len(relas)): - if relas[j][0] == relas[i][1]: # i的父圈就是j(i是j的子圈) - if polygons[i] is not None and polygons[j] is not None: - min_i, min_o = __find_min_point(polygons[i], polygons[j]) - # 改变顺序 - polygons[i] = __change_list(polygons[i], min_i) - polygons[j] = __change_list(polygons[j], min_o) - # 连接 - if min_i != -1 and len(polygons[i]) > 0: - polygons[j].extend(polygons[i]) # 连接内圈 - polygons[i] = None - polygons = list(filter(None, polygons)) # 清除加到外圈的内圈多边形 - return polygons - else: - print("没有标签范围,无法生成边界") - return None - - -def __change_list(polygons, idx): - if idx == -1: - return polygons - s_p = polygons[:idx] - polygons = polygons[idx:] - polygons.extend(s_p) - polygons.append(polygons[0]) # 闭合圈 - return polygons - - -def __find_min_point(i_list, o_list): - min_dis = 1e7 - idx_i = -1 - idx_o = -1 - for i in range(len(i_list)): - for o in range(len(o_list)): - dis = math.sqrt( - (i_list[i][0] - o_list[o][0]) ** 2 + (i_list[i][1] - o_list[o][1]) ** 2 - ) - if dis <= min_dis: - min_dis = dis - idx_i = i - idx_o = o - return idx_i, idx_o - - -# 根据三点坐标计算夹角 -def __cal_ang(p1, p2, p3): - eps = 1e-12 - a = math.sqrt((p2[0] - p3[0]) * (p2[0] - p3[0]) + (p2[1] - p3[1]) * (p2[1] - p3[1])) - b = math.sqrt((p1[0] - p3[0]) * (p1[0] - p3[0]) + (p1[1] - p3[1]) * (p1[1] - p3[1])) - c = math.sqrt((p1[0] - p2[0]) * (p1[0] - p2[0]) + (p1[1] - p2[1]) * (p1[1] - p2[1])) - ang = math.degrees( - math.acos((b ** 2 - a ** 2 - c ** 2) / (-2 * a * c + eps)) - ) # p2对应 - return ang - - -# 计算两点距离 -def __cal_dist(p1, p2): - return math.sqrt((p1[0] - p2[0]) ** 2 + (p1[1] - p2[1]) ** 2) - - -# 边界点简化 -def approx_poly_DIY(contour, min_dist=10, ang_err=5): - # print(contour.shape) # N, 1, 2 - cs = [contour[i][0] for i in range(contour.shape[0])] - ## 1. 先删除两个相近点与前后两个点角度接近的点 - i = 0 - while i < len(cs): - try: - j = (i + 1) if (i != len(cs) - 1) else 0 - if __cal_dist(cs[i], cs[j]) < min_dist: - last = (i - 1) if (i != 0) else (len(cs) - 1) - next = (j + 1) if (j != len(cs) - 1) else 0 - ang_i = __cal_ang(cs[last], cs[i], cs[next]) - ang_j = __cal_ang(cs[last], cs[j], cs[next]) - # print(ang_i, ang_j) # 角度值为-180到+180 - if abs(ang_i - ang_j) < ang_err: - # 删除距离两点小的 - dist_i = __cal_dist(cs[last], cs[i]) + __cal_dist(cs[i], cs[next]) - dist_j = __cal_dist(cs[last], cs[j]) + __cal_dist(cs[j], cs[next]) - if dist_j < dist_i: - del cs[j] - else: - del cs[i] - else: - i += 1 - else: - i += 1 - except: - i += 1 - ## 2. 再删除夹角接近180度的点 - i = 0 - while i < len(cs): - try: - last = (i - 1) if (i != 0) else (len(cs) - 1) - next = (i + 1) if (i != len(cs) - 1) else 0 - ang_i = __cal_ang(cs[last], cs[i], cs[next]) - if abs(ang_i) > (180 - ang_err): - del cs[i] - else: - i += 1 - except: - # i += 1 - del cs[i] - res = np.array(cs).reshape([-1, 1, 2]) - return res \ No newline at end of file diff --git a/buildseg/utils/convert.py b/buildseg/utils/convert.py index 9ffeeb0..df79b0a 100644 --- a/buildseg/utils/convert.py +++ b/buildseg/utils/convert.py @@ -41,7 +41,7 @@ def layer2array(sample_path, band_list, row=None, col=None, grid_size=[512, 512] array = np.stack(array_list, axis=2) else: array = raster_to_uint8(__get_grid(gd, row, col, \ - width, height, grid_size, overlap)) + width, height, grid_size, overlap)) del gd return array diff --git a/buildseg/utils/shape.py b/buildseg/utils/shape.py index cecc4d3..d96469c 100644 --- a/buildseg/utils/shape.py +++ b/buildseg/utils/shape.py @@ -1,5 +1,6 @@ import os import os.path as osp +import numpy as np from qgis.utils import iface try: @@ -12,9 +13,8 @@ def __mask2tif(mask, tmp_path, proj, geot): row, columns = mask.shape[:2] - dim = 1 driver = gdal.GetDriverByName("GTiff") - dst_ds = driver.Create(tmp_path, columns, row, dim, gdal.GDT_UInt16) + 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) @@ -23,8 +23,12 @@ def __mask2tif(mask, tmp_path, proj, geot): def polygonize_raster(mask, shp_save_path, proj, geot, rm_tmp=True, display=True): - tmp_path = shp_save_path.replace(".shp", ".tif") - ds = __mask2tif(mask, tmp_path, proj, geot) + if type(mask) is np.ndarray: + tmp_path = shp_save_path.replace(".shp", ".tif") + ds = __mask2tif(mask, tmp_path, proj, geot) + else: + tmp_path = mask.file_name + ds = mask.gdal_data srcband = ds.GetRasterBand(1) maskband = srcband.GetMaskBand() gdal.SetConfigOption("GDAL_FILENAME_IS_UTF8", "YES") @@ -52,6 +56,7 @@ def polygonize_raster(mask, shp_save_path, proj, geot, rm_tmp=True, display=True dst_ds.Destroy() ds = None if rm_tmp: + mask.close() os.remove(tmp_path) if display: iface.addVectorLayer(shp_save_path, "deepbands", "ogr") diff --git a/buildseg/utils/simplify.py b/buildseg/utils/simplify.py index 890de37..a61ce12 100644 --- a/buildseg/utils/simplify.py +++ b/buildseg/utils/simplify.py @@ -18,12 +18,9 @@ def simplify_polygon(infile, outfile, threshold=0.2): 'OUTPUT':outfile}) -def dowm_sample(file_path, scale=0.5): +def dowm_sample(file_path, down_sample_save, scale=0.5): if scale == 1.0: return file_path - path, named = osp.split(file_path) - name, ext = osp.splitext(named) - down_sample_save = osp.join(path, (name + "_down_sample" + ext)) dataset = gdal.Open(file_path) band_count = dataset.RasterCount cols = dataset.RasterXSize diff --git a/buildseg/utils/splicing.py b/buildseg/utils/splicing.py index bacadc5..c420dc3 100644 --- a/buildseg/utils/splicing.py +++ b/buildseg/utils/splicing.py @@ -1,5 +1,9 @@ import numpy as np -# import math + +try: + from osgeo import gdal +except ImportError: + import gdal def create_grids(ysize, xsize, grid_size=[512, 512], overlap=[24, 24]): @@ -8,39 +12,84 @@ def create_grids(ysize, xsize, grid_size=[512, 512], overlap=[24, 24]): overlap = np.array(overlap) grid_count = np.ceil(img_size / (grid_size - overlap)) grid_count = grid_count.astype("uint16") - mask_grids = [[np.zeros(grid_size) \ - for _ in range(grid_count[1])] for _ in range(grid_count[0])] - return list(grid_count), mask_grids + # mask_grids = [[np.zeros(grid_size) \ + # for _ in range(grid_count[1])] for _ in range(grid_count[0])] + # return list(grid_count), mask_grids + return list(grid_count) -def splicing_grids(img_list, ysize, xsize, grid_size=[512, 512], overlap=[24, 24]): - raw_size = np.array([ysize, xsize]) - grid_size = np.array(grid_size) - overlap = np.array(overlap) - h, w = grid_size - # row = math.ceil(raw_size[0] / h) - # col = math.ceil(raw_size[1] / w) - row, col = len(img_list), len(img_list[0]) - # print("row, col:", row, col) - result_1 = np.zeros((h * row, w * col), dtype=np.uint8) - result_2 = result_1.copy() - for i in range(row): - for j in range(col): - # print("h, w:", h, w) - ih, iw = img_list[i][j].shape[:2] - im = np.zeros(grid_size) - im[:ih, :iw] = img_list[i][j] - start_h = (i * h) if i == 0 else (i * (h - overlap[0])) - end_h = start_h + h - start_w = (j * w) if j == 0 else (j * (w - overlap[1])) - end_w = start_w + w - # print("se: ", start_h, end_h, start_w, end_w) - # Or operation on overlapping areas - if (i + j) % 2 == 0: - result_1[start_h: end_h, start_w: end_w] = im - else: - result_2[start_h: end_h, start_w: end_w] = im - # print("r, c, k:", i_r, i_c, k) - result = np.where(result_2 != 0, result_2, result_1) - result = result[:raw_size[0], :raw_size[1]] - return result \ No newline at end of file +# def splicing_grids(img_list, ysize, xsize, grid_size=[512, 512], overlap=[24, 24]): +# raw_size = np.array([ysize, xsize]) +# grid_size = np.array(grid_size) +# overlap = np.array(overlap) +# h, w = grid_size +# # row = math.ceil(raw_size[0] / h) +# # col = math.ceil(raw_size[1] / w) +# row, col = len(img_list), len(img_list[0]) +# # print("row, col:", row, col) +# result_1 = np.zeros((h * row, w * col), dtype=np.uint8) +# result_2 = result_1.copy() +# for i in range(row): +# for j in range(col): +# # print("h, w:", h, w) +# ih, iw = img_list[i][j].shape[:2] +# im = np.zeros(grid_size) +# im[:ih, :iw] = img_list[i][j] +# start_h = (i * h) if i == 0 else (i * (h - overlap[0])) +# end_h = start_h + h +# start_w = (j * w) if j == 0 else (j * (w - overlap[1])) +# end_w = start_w + w +# # print("se: ", start_h, end_h, start_w, end_w) +# # Or operation on overlapping areas +# if (i + j) % 2 == 0: +# result_1[start_h: end_h, start_w: end_w] = im +# else: +# result_2[start_h: end_h, start_w: end_w] = im +# # print("r, c, k:", i_r, i_c, k) +# result = np.where(result_2 != 0, result_2, result_1) +# result = result[:raw_size[0], :raw_size[1]] +# return result + + +class Mask(object): + def __init__(self, file_name, geoinfo, grid_size=[512, 512], overlap=[24, 24]) -> None: + self.file_name = file_name + self.raw_size = np.array([geoinfo["row"], geoinfo["col"]]) + self.grid_size = np.array(grid_size) + self.overlap = np.array(overlap) + driver = gdal.GetDriverByName("GTiff") + self.dst_ds = driver.Create(file_name, geoinfo["col"], geoinfo["row"], 1, gdal.GDT_UInt16) + self.dst_ds.SetGeoTransform(geoinfo["geot"]) + self.dst_ds.SetProjection(geoinfo["proj"]) + self.band = self.dst_ds.GetRasterBand(1) + self.band.WriteArray(np.zeros((self.raw_size[0], self.raw_size[1]), dtype="uint8")) + + def write_grid(self, grid, i, j): + h, w = self.grid_size + start_h = (i * h) if i == 0 else (i * (h - self.overlap[0])) + end_h = start_h + h + if end_h > self.raw_size[0]: + win_ysize = int(self.raw_size[0] - start_h) + else: + win_ysize = int(self.grid_size[1]) + start_w = (j * w) if j == 0 else (j * (w - self.overlap[1])) + end_w = start_w + w + if end_w > self.raw_size[1]: + win_xsize = int(self.raw_size[1] - start_w) + else: + win_xsize = int(self.grid_size[0]) + over_grid = self.band.ReadAsArray(xoff=int(start_w), yoff=int(start_h), \ + win_xsize=win_xsize, win_ysize=win_ysize) + h, w = over_grid.shape + # print(h, w) + over_grid += grid[:h , :w] + over_grid[over_grid > 0] = 1 + self.band.WriteArray(over_grid, int(start_w), int(start_h)) + self.dst_ds.FlushCache() + + @property + def gdal_data(self): + return self.dst_ds + + def close(self): + self.dst_ds = None \ No newline at end of file diff --git a/docs/README_CN.md b/docs/README_CN.md index 8cc2015..259c820 100644 --- a/docs/README_CN.md +++ b/docs/README_CN.md @@ -79,18 +79,23 @@ git clone git@github.com:deepbands/buildseg.git ### v0.2 - [x] 环境中依赖包的检查。 + - [x] 添加例如ViT等的其他模型。 + - [x] 添加描述说明: - [x] 关于如何在AI Studio以及本地训练自己的数据。 - [x] 关于不同模型(论文链接)。 -- [ ] 加速: + +- [x] 加速和减小内存: - [x] 设置PaddlePaddle预测引擎。 - [x] 添加最大像素值计算或者使用GDAL的`translat / warp`来减小栅格大小 - - [ ] 使用分块拼接和保存。 -- [ ] 添加对在线地图瓦片的支持: - - [ ] 可以对保存在内存中的栅格图像进行建筑提取。 - - [ ] 添加矢量边界的选择。 + - [x] 使用分块拼接和保存。 + - [ ] 测试: - [x] 在 Windows 10/11上。 - [ ] 在Linux上。 - [ ] 在mac OS Big Sur+上。 + +- [ ] 添加对在线地图瓦片的支持: + - [ ] 可以对保存在内存中的栅格图像进行建筑提取。 + - [ ] 添加矢量边界的选择。