From 1275984da65c525aad7b69ca49428b47bcc83f71 Mon Sep 17 00:00:00 2001 From: jingpengw Date: Tue, 7 Apr 2020 22:22:25 -0400 Subject: [PATCH 1/2] setup ids using json file --- Dockerfile | 2 +- chunkflow/flow/flow.py | 9 +++++---- chunkflow/flow/mesh.py | 26 +++++++++++++++++++------- 3 files changed, 25 insertions(+), 12 deletions(-) diff --git a/Dockerfile b/Dockerfile index 8b837b14..5d92a107 100755 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # backend: base | pytorch | pznet | pytorch-cuda9 -ARG BACKEND=pytorch +ARG BACKEND=base FROM seunglab/chunkflow:${BACKEND} diff --git a/chunkflow/flow/flow.py b/chunkflow/flow/flow.py index 5347aebb..a92daff2 100755 --- a/chunkflow/flow/flow.py +++ b/chunkflow/flow/flow.py @@ -3,6 +3,7 @@ import sys from functools import update_wrapper, wraps from time import time + import numpy as np import click @@ -988,7 +989,7 @@ def copy_var(tasks, name, from_name, to_name): @click.option('--batch-size', '-b', type=int, default=1, help='mini batch size of input patch.') @click.option('--bump', type=click.Choice(['wu', 'zung']), default='wu', - help='bump function type. only works with pytorch-multitask backend.') + help='bump function type (only support wu now!).') @click.option('--mask-output-chunk/--no-mask-output-chunk', default=False, help='mask output chunk will make the whole chunk like one output patch. ' + 'This will also work with non-aligned chunk size.') @@ -1150,15 +1151,15 @@ def crop_margin(tasks, name, margin_size, type=int, default=None, help='do not mesh segments with voxel number less than threshold.') @click.option('--ids', type=str, default=None, help='a list of segment ids to mesh. This is for sparse meshing. ' + - 'The ids should be separated by comma without space, such as "34,56,78,90"') + 'The ids should be separated by comma without space, such as "34,56,78,90"' + + ' it can also be a json file contains a list of ids. The json file should be '+ + 'put in the output_path.') @click.option('--manifest/--no-manifest', default=False, help='create manifest file or not.') @operator def mesh(tasks, name, input_chunk_name, mip, voxel_size, output_path, output_format, simplification_factor, max_simplification_error, dust_threshold, ids, manifest): """Perform meshing for segmentation chunk.""" - if ids: - ids = set([int(id) for id in ids.split(',')]) if mip is None: mip = state['mip'] diff --git a/chunkflow/flow/mesh.py b/chunkflow/flow/mesh.py index 51a303d5..9d6e94c6 100644 --- a/chunkflow/flow/mesh.py +++ b/chunkflow/flow/mesh.py @@ -24,16 +24,16 @@ def __init__(self, simplification_factor: int = 100, max_simplification_error: int = 8, dust_threshold: int = None, - ids: set = None, + ids: str = None, manifest: bool = False, name: str = 'meshing', verbose: bool = True): """ Parameters ------------ - output_path: + output_path: path to store mesh files - output_format: + output_format: format of output {'ply', 'obj', 'precomputed'} voxel_size: size of voxels @@ -62,9 +62,8 @@ def __init__(self, self.output_path = output_path self.output_format = output_format self.dust_threshold = dust_threshold - self.ids = ids self.manifest = manifest - + if manifest: assert output_format == 'precomputed' @@ -86,6 +85,19 @@ def __init__(self, self.mesher = Mesher(voxel_size[::-1]) self.storage = Storage(mesh_path) + + if ids.endswith('.json'): + # assume that ids is a json file in the storage path + json_storage = Storage(output_path) + ids_str = json_storage.get_file(ids) + self.ids = set(json.loads(ids_str)) + assert len(self.ids) > 0 + if self.verbose: + print(f'number of selected objects: {len(self.ids)}') + else: + # a simple string, like "34,45,56,23" + # this is used for small object numbers + self.ids = set([int(id) for id in ids.split(',')]) def _get_mesh_data(self, obj_id, offset): mesh = self.mesher.get_mesh( @@ -116,8 +128,8 @@ def _remove_dust(self, seg: np.ndarray): if self.dust_threshold or self.ids: segids, voxel_nums = np.unique(seg, return_counts=True) - dust_segids = [sid for sid, ct in - zip(segids, voxel_nums) if ct < self.dust_threshold] + dust_segids = [sid for sid, ct in + zip(segids, voxel_nums) if ct < self.dust_threshold] seg = fastremap.mask(seg, dust_segids, in_place=True) return seg From 2c2ac30775801409e17be381ccf1fdf9aafa33c5 Mon Sep 17 00:00:00 2001 From: jingpengw Date: Tue, 7 Apr 2020 23:01:51 -0400 Subject: [PATCH 2/2] fix ids is None case --- chunkflow/flow/mesh.py | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/chunkflow/flow/mesh.py b/chunkflow/flow/mesh.py index 9d6e94c6..e1d753f5 100644 --- a/chunkflow/flow/mesh.py +++ b/chunkflow/flow/mesh.py @@ -63,7 +63,8 @@ def __init__(self, self.output_format = output_format self.dust_threshold = dust_threshold self.manifest = manifest - + self.ids = ids + if manifest: assert output_format == 'precomputed' @@ -86,18 +87,19 @@ def __init__(self, self.storage = Storage(mesh_path) - if ids.endswith('.json'): - # assume that ids is a json file in the storage path - json_storage = Storage(output_path) - ids_str = json_storage.get_file(ids) - self.ids = set(json.loads(ids_str)) - assert len(self.ids) > 0 - if self.verbose: - print(f'number of selected objects: {len(self.ids)}') - else: - # a simple string, like "34,45,56,23" - # this is used for small object numbers - self.ids = set([int(id) for id in ids.split(',')]) + if ids: + if ids.endswith('.json'): + # assume that ids is a json file in the storage path + json_storage = Storage(output_path) + ids_str = json_storage.get_file(ids) + self.ids = set(json.loads(ids_str)) + assert len(self.ids) > 0 + if self.verbose: + print(f'number of selected objects: {len(self.ids)}') + else: + # a simple string, like "34,45,56,23" + # this is used for small object numbers + self.ids = set([int(id) for id in ids.split(',')]) def _get_mesh_data(self, obj_id, offset): mesh = self.mesher.get_mesh(