Пример #1
0
    def compute_supervoxels(self):

        with progress(total=4) as pbar:
            pbar.set_description("Refreshing")
            pbar.update(1)
                
            # src = [
            #    DataModel.g.dataset_uri("features/" + s) for s in [self.svsource.value()]
            # ]
            src = DataModel.g.dataset_uri(self.svsource.value(), group="features")
            dst = DataModel.g.dataset_uri(self.svid, group="superregions")
            logger.debug(f"Compute sv: Src {src} Dst {dst}")

            from survos2.model import Workspace

            ws = Workspace(DataModel.g.current_workspace)
            num_chunks = np.prod(np.array(ws.metadata()["chunk_grid"]))
            chunk_size = ws.metadata()["chunk_size"]
            logger.debug(
                f"Using chunk_size {chunk_size} to compute number of supervoxel segments for num_chunks: {num_chunks}."
            )

            with DatasetManager(src, out=None, dtype="float32", fillvalue=0) as DM:
                src_dataset_shape = DM.sources[0][:].shape

            # n_segments = int(np.prod(chunk_size) // (self.svshape.value() ** 3))
            pbar.update(1)
            n_segments = int(np.prod(src_dataset_shape) / self.svshape.value() ** 3)

            if self.int64_checkbox.value():
                out_dtype = "uint64"
            else:
                out_dtype = "uint32"

            params = dict(
                src=src,
                dst=dst,
                compactness=round(self.svcompactness.value() / 100, 3),
                # shape=self.svshape.value(),
                n_segments=n_segments,
                spacing=self.svspacing.value(),
                modal=True,
                out_dtype=out_dtype,
            )
            logger.debug(f"Compute supervoxels with params {params}")

            pbar.update(1)

            result = Launcher.g.run("superregions", "supervoxels", **params)
            if result is not None:
                pbar.update(1)
Пример #2
0
def frontend(viewer):
    logger.info(f"Frontend loading workspace: {DataModel.g.current_workspace}")
    cfg.base_dataset_shape = (100, 100, 100)
    cfg.slice_max = 100

    cfg.current_mode = "paint"
    cfg.label_ids = [
        0,
    ]
    cfg.retrieval_mode =  Config["volume_mode"] # "volume"  # volume_http | volume | slice
    cfg.current_slice = 0
    cfg.current_orientation = 0

    cfg.current_feature_name = "001_raw"
    cfg.current_annotation_name = None
    cfg.current_pipeline_name = None
    cfg.current_regions_name = None
    cfg.current_analyzers_name = None

    cfg.emptying_viewer = False
    cfg.three_dim = False

    cfg.current_regions_dataset = None
    cfg.current_supervoxels = None
    cfg.supervoxels_cache = None
    cfg.supervoxels_cached = False
    cfg.supervoxel_size = 10
    cfg.local_sv = True
    cfg.pause_save = False
    cfg.remote_annotation = True
    cfg.object_offset = (0, 0, 0) 
    cfg.num_undo = 0

    label_dict = {
        "level": "001_level",
        "idx": 1,
        "color": "#000000",
    }
    cfg.label_value = label_dict

    cfg.order = (0, 1, 2)
    cfg.group = "main"

    # SuRVoS controls
    dw = AttrDict()
    dw.ppw = PluginPanelWidget()  # Main SuRVoS panel
    dw.bpw = ButtonPanelWidget()  # Additional controls
    dw.ppw.setMinimumSize(QSize(450, 750))

    if DataModel.g.current_workspace != '':
        ws = Workspace(DataModel.g.current_workspace)
        dw.ws = ws
    
    dw.datamodel = DataModel.g
    dw.Launcher = Launcher
    viewer.theme = "dark"

    def set_paint_params(msg):
        if not cfg.emptying_viewer:
            logger.debug(f"set_paint_params {msg['paint_params']}")
            paint_params = msg["paint_params"]
            label_value = paint_params["label_value"]

            if label_value is not None and len(viewer.layers.selection) > 0:
                _set_params(label_value, paint_params)

    def _set_params(label_value, paint_params):
        anno_layer = [v for v in viewer.layers if v.name == cfg.current_annotation_name]

        if len(anno_layer) > 0:
            if not cfg.remote_annotation:
                if cfg.retrieval_mode != 'slice':
                    cfg.ppw.clientEvent.emit(
                                {
                                    "source": "save_annotation",
                                    "data": "save_annotation",
                                    "value": None,
                                }
                            )
            cfg.local_sv = False
        
            anno_layer = anno_layer[0]
            cfg.label_ids = list(np.unique(anno_layer))
            anno_layer.mode = "paint"
            cfg.current_mode = "paint"
            anno_layer.selected_label = int(label_value["idx"]) - 1
            cfg.label_value = label_value
            anno_layer.brush_size = int(paint_params["brush_size"])

            if paint_params["current_supervoxels"] is not None:
                sv_name = ntpath.basename(paint_params["current_supervoxels"])
                existing_sv_layer = [v for v in viewer.layers if v.name == sv_name]
                if not existing_sv_layer:
                    view_regions(viewer, {"region_id": sv_name})
            else:
                logger.debug("paint_params['current_supervoxels'] is None")

            viewer.layers.selection.active = anno_layer


    def update_annotations(msg):
        logger.debug(f"update_annotation {msg}")
        
        if cfg.local_sv:
            update_annotation_layer_in_viewer(msg["level_id"], cfg.anno_data)
        else:
            src = DataModel.g.dataset_uri(msg["level_id"], group="annotations")
            with DatasetManager(src, out=None, dtype="float32", fillvalue=0) as DM:
                src_annotations_dataset = DM.sources[0][:]
                src_arr = get_array_from_dataset(src_annotations_dataset)
            update_annotation_layer_in_viewer(msg["level_id"], src_arr)


    def update_annotation_layer_in_viewer(layer_name, src_arr):
        existing_layer = [v for v in viewer.layers if v.name == layer_name]
        if existing_layer:
            existing_layer[0].data = src_arr.astype(np.int32) & 15

    def refresh_annotations_in_viewer(msg):
        logger.debug(f"refresh_annotation {msg['level_id']}")
        if not cfg.emptying_viewer:
            try:
                cfg.current_annotation_name = msg["level_id"]

                if cfg.local_sv:
                    anno_layer = [v for v in viewer.layers if v.name == cfg.current_annotation_name]
                    if len(anno_layer) == 0:
                        src_arr, src_annotations_dataset = get_level_from_server(
                            msg, retrieval_mode=cfg.retrieval_mode
                        )    
                        cfg.anno_data = src_arr

                    print("Refresh from server paused, updating annotation from cfg.anno_data")
                    if 'prev_arr' in cfg: 
                        src_arr = cfg.prev_arr
                    else:
                        src_arr = cfg.anno_data
                        
                    if cfg.retrieval_mode != 'slice':
                        print("Saving annotation")
                        cfg.ppw.clientEvent.emit({
                                    "source": "save_annotation",
                                    "data": "save_annotation",
                                    "value": None,
                                }
                            )
                else:
                    src_arr, src_annotations_dataset = get_level_from_server(
                        msg, retrieval_mode=cfg.retrieval_mode
                    )

                result = Launcher.g.run(
                    "annotations", "get_levels", workspace=DataModel.g.current_workspace
                )
  
                if result:
                    return _refresh_annotations_in_viewer(
                        result, msg, src_arr
                    )

            except Exception as e:
                print(f"Exception {e}")

    def _refresh_annotations_in_viewer(result, msg, src_arr):
        #logger.debug(f"Refresh annotations in viewer {src_arr.shape}")
        cmapping, label_ids = get_color_mapping(result, msg["level_id"])
        #logger.debug(f"Label ids {label_ids}")
        cfg.label_ids = label_ids
        existing_layer = [v for v in viewer.layers if v.name == msg["level_id"]]
        
        # some defaults
        sel_label = 1
        brush_size = 10

        if existing_layer and cfg.current_annotation_name:
            existing_layer[0].data = src_arr.astype(np.int32) & 15
            label_layer = existing_layer[0]
            existing_layer[0].color = cmapping
        elif cfg.current_annotation_name:
            #print(f"Adding labels {src_arr.shape} {cmapping }")
            label_layer = viewer.add_labels(
            src_arr & 15, name=msg["level_id"], color=cmapping
            )
            label_layer.mode = cfg.current_mode
            label_layer.brush_size = brush_size
        
        if cfg.label_value is not None:
            label_layer.selected_label = int(cfg.label_value["idx"]) - 1

        #print(f"Returning label layer {label_layer}")
        return label_layer

    def setup_paint_undo_remote(label_layer):
        @label_layer.bind_key("Control-Z", overwrite=True)
        def undo(v):
            logger.info("Undoing")
            if cfg.num_undo == 0:
                level = cfg.current_annotation_name
                params = dict(workspace=True, level=level)
                result = Launcher.g.run("annotations", "annotate_undo", **params)
                cfg.ppw.clientEvent.emit(
                    {
                        "source": "annotations",
                        "data": "update_annotations",
                        "level_id": level,
                    }
                )
               
                cfg.num_undo += 1

    def setup_paint_undo_local(label_layer):
        @label_layer.bind_key("Control-Z", overwrite=True)
        def undo(v):
            #logger.info("Undoing local annotation")
            if cfg.num_undo == 0:
                print(cfg.anno_data)
                #cfg.anno_data = cfg.anno_data >> _MaskSize
                cfg.anno_data = cfg.prev_arr.copy()
                cfg.num_undo += 1
                existing_layer = [v for v in viewer.layers if v.name == cfg.current_annotation_name]
                if existing_layer:
                    existing_layer[0].data = cfg.anno_data.astype(np.int32) & 15
                label_layer.undo()
                if cfg.retrieval_mode != 'slice':
                    logger.debug("Saving annotation")
                    cfg.ppw.clientEvent.emit({
                                "source": "save_annotation",
                                "data": "save_annotation",
                                "value": None,
                    })


    def setup_painting_layer(label_layer, msg, parent_level, parent_label_idx):
        if not hasattr(label_layer, 'already_init'):
            @label_layer.mouse_drag_callbacks.append
            def painting_layer(layer, event):
                cfg.prev_arr = label_layer.data.copy()
                drag_pts = []
                coords = np.round(layer.world_to_data(viewer.cursor.position)).astype(
                    np.int32
                )
                try:
                    if cfg.retrieval_mode == "slice":
                        drag_pt = [coords[0], coords[1]]
                    elif cfg.retrieval_mode == "volume" or cfg.retrieval_mode == "volume_http":
                        drag_pt = [coords[0], coords[1], coords[2]]
                    drag_pts.append(drag_pt)
                    yield

                    if layer.mode == "fill" or layer.mode == "pick":
                        layer.mode = "paint"
                    if layer.mode == "paint" or layer.mode == "erase":
                        while event.type == "mouse_move":
                            
                            coords = np.round(
                                layer.world_to_data(viewer.cursor.position)
                            ).astype(np.int32)

                            if cfg.retrieval_mode == "slice":
                                drag_pt = [coords[0], coords[1]]
                            elif cfg.retrieval_mode == "volume" or cfg.retrieval_mode == "volume_http":
                                drag_pt = [coords[0], coords[1], coords[2]]
                            drag_pts.append(drag_pt)
                            yield

                        if len(drag_pts) >= 0:
                            #top_layer = viewer.layers[-1]
                            #layer_name = top_layer.name  # get last added layer name
                            anno_layer = [v for v in viewer.layers if v.name == cfg.current_annotation_name]
                            if len(anno_layer) > 0:
                                anno_layer = anno_layer[0]
                                #anno_layer = next(l for l in viewer.layers if l.name == cfg.current_annotation_name)
                    
                                def update_anno(msg):
                                    if cfg.local_sv:
                                        
                                        src_arr = cfg.anno_data 
                                    else:
                                        src_arr, _ = get_level_from_server(
                                            msg, retrieval_mode=cfg.retrieval_mode
                                        )
                                    update_annotation_layer_in_viewer(msg["level_id"], src_arr)

                                update = partial(update_anno, msg=msg)
                                viewer_order = viewer.window.qt_viewer.viewer.dims.order
                                paint_strokes_worker = paint_strokes(
                                    msg,
                                    drag_pts,
                                    anno_layer,
                                    cfg.parent_level,
                                    cfg.parent_label_idx,
                                    viewer_order,
                                )
                                paint_strokes_worker.returned.connect(update)
                                paint_strokes_worker.start()
                                
                                cfg.num_undo = 0                              
                        else:
                            
                            cfg.ppw.clientEvent.emit(
                                {
                                    "source": "annotations",
                                    "data": "update_annotations",
                                    "level_id": msg["level_id"],
                                }
                            )
                except ValueError as e:
                    print(e)
        label_layer.already_init = 1

    def paint_annotations(msg):
        if not cfg.emptying_viewer:
            #logger.debug(f"paint_annotation {msg['level_id']}")
            
            try:
                label_layer = refresh_annotations_in_viewer(msg)
                #print(f"paint_annotations label_layer {label_layer}")
                sel_label = (
                    int(cfg.label_value["idx"]) if cfg.label_value is not None else 1
                )
                if msg["level_id"] is not None:
                    params = dict(
                        workspace=True, level=msg["level_id"], label_idx=sel_label
                    )
                    result = Launcher.g.run("annotations", "get_label_parent", **params)
                    parent_level = result[0]
                    parent_label_idx = result[1]
                    cfg.parent_level = parent_level
                    cfg.parent_label_idx = parent_label_idx
                    setup_paint_undo_local(label_layer)
                    setup_painting_layer(label_layer, msg, parent_level, parent_label_idx)

            except Exception as e:
                print(f"Exception: {e}")
    

    def set_session(msg):
        logger.debug(f"Set session to {msg['session']}")
        DataModel.g.current_session = msg["session"]

    def set_workspace(msg):
        logger.debug(f"Set workspace to {msg['workspace']}")
        # set on client
        DataModel.g.current_workspace = msg["workspace"]
        # set on server
        params = dict(workspace=msg["workspace"])
        result = Launcher.g.run("workspace", "set_workspace", **params)
        viewer.title = msg["workspace"]

    def view_patches(msg):
        from survos2.entity.patches import load_patch_vols
        logger.debug(f"view_patches {msg['patches_fullname']}")
        img_vols, label_vols = load_patch_vols(msg["patches_fullname"])
        viewer.add_image(img_vols, name="Patch Image")
        viewer.add_image(label_vols, name="Patch Label")

    def save_annotation(msg):
        logger.info(f"Save annotation {msg}")
        annotation_layer = [
            v for v in viewer.layers if v.name == cfg.current_annotation_name
        ]
        if len(annotation_layer) == 1:
            logger.info(
                f"Updating annotation {cfg.current_annotation_name} with label image {annotation_layer}"
            )
            
            result = Launcher.g.post_array(annotation_layer[0].data, 
                group='annotations', 
                workspace=DataModel.g.current_workspace, 
                name=cfg.current_annotation_name)
        else:
            logger.info("save_annotation couldn't find annotation in viewer")


    def transfer_layer(msg):
        with progress(total=1) as pbar:
            pbar.set_description("Transferring layer")
            logger.debug(f"transfer_layer {msg}")
            selected_layer = viewer.layers.selection.pop()
            if isinstance(selected_layer, Labels):
                _transfer_labels(selected_layer)
            elif isinstance(selected_layer, Points):
                _transfer_points(selected_layer)
            elif isinstance(selected_layer, Image):
                _transfer_features_http(selected_layer)
            else:
                logger.debug("Unsupported layer type.")
            pbar.update(1)
            processEvents({"data": "refresh"})

    def jump_to_slice(msg):
        cfg.supervoxels_cached = False
        cfg.retrieval_mode = "slice"
        cfg.current_slice = int(msg["frame"])
        
        existing_feature_layer = [
            v for v in viewer.layers if v.name == cfg.current_feature_name
        ]

        if existing_feature_layer:
            features_src = DataModel.g.dataset_uri(
                cfg.current_feature_name, group="features"
            )
            params = dict(
                workpace=True,
                src=features_src,
                slice_idx=cfg.current_slice,
                order=cfg.order,
            )
            result = Launcher.g.run("features", "get_slice", **params)
            if result:
                src_arr = decode_numpy_slice(result)
                existing_feature_layer[0].data = src_arr.copy()

        existing_regions_layer = [
            v for v in viewer.layers if v.name == cfg.current_regions_name
        ]
        if existing_regions_layer:
            regions_src = DataModel.g.dataset_uri(
                cfg.current_regions_name, group="superregions"
            )
            params = dict(
                workpace=True,
                src=regions_src,
                slice_idx=cfg.current_slice,
                order=cfg.order,
            )
            result = Launcher.g.run("superregions", "get_slice", **params)
            if result:
                src_arr = decode_numpy(result)
                src_arr = find_boundaries(src_arr) * 1.0
                existing_regions_layer[0].data = src_arr.copy()
                existing_regions_layer[0].opacity = 0.3

        existing_level_layer = [
            v for v in viewer.layers if v.name == cfg.current_annotation_name
        ]
        if existing_level_layer and cfg.current_annotation_name is not None:
            paint_annotations({"level_id": cfg.current_annotation_name})

        existing_pipeline_layer = [
            v for v in viewer.layers if v.name == cfg.current_pipeline_name
        ]

        if existing_pipeline_layer:
            print(f"loading pipeline {cfg.current_pipeline_name}")
            pipeline_src = DataModel.g.dataset_uri(
                cfg.current_pipeline_name, group="pipelines"
            )
            params = dict(
                workpace=True,
                src=pipeline_src,
                slice_idx=cfg.current_slice,
                order=cfg.order,
            )
            result = Launcher.g.run("features", "get_slice", **params)
            if result:
                src_arr = decode_numpy(result).astype(np.int32)
                existing_pipeline_layer[0].data = src_arr.copy()
    
        existing_analyzers_layer = [
            v for v in viewer.layers if v.name == cfg.current_analyzers_name
        ]

        if existing_analyzers_layer:
            print(f"Jumping to analyzer slice {cfg.current_analyzers_name}")
            analyzers_src = DataModel.g.dataset_uri(
                cfg.current_analyzers_name, group="analyzer"
            )
            params = dict(
                workpace=True,
                src=analyzers_src,
                slice_idx=cfg.current_slice,
                order=cfg.order,
            )
            result = Launcher.g.run("features", "get_slice", **params)
            if result:
                src_arr = decode_numpy(result).astype(np.int32)
                existing_analyzers_layer[0].data = src_arr.copy()

    def make_roi_ws(msg):
        logger.debug(f"Goto roi: {msg}")
        params = dict(
            workspace=True,
            current_workspace_name=DataModel.g.current_workspace,
            feature_id="001_raw",
            roi=msg["roi"],
        )
        result = Launcher.g.run("workspace", "make_roi_ws", **params)
        #if result:
        #    logger.debug(f"Switching to make_roi_ws created workspace {result}")
        #    DataModel.g.current_workspace = result
        #    processEvents({"data": "refresh"})

    def get_crop(msg):
        logger.debug(f"Getting crop roi: {msg}")
        features_src = DataModel.g.dataset_uri(msg["feature_id"], group="features")
        params = dict(workpace=True, src=features_src, roi=(0, 0, 0, 100, 100, 100))
        result = Launcher.g.run("features", "get_crop", **params)
        if result:
            src_arr = decode_numpy(result)
            viewer.add_image(src_arr, name=msg["feature_id"])

    def show_roi(msg):
        logger.info(f"Showing ROI {msg['selected_roi']}")
        z, x, y = msg["selected_roi"]
        existing_feature_layer = [
            v for v in viewer.layers if v.name == cfg.current_feature_name
        ]
        viewer.camera.center = (z, x, y)
        viewer.dims.set_current_step(0, z)
        viewer.camera.zoom = 4

    def processEvents(msg):
        logger.debug(msg)
        if msg["data"] == "jump_to_slice":
            jump_to_slice(msg)
        elif msg["data"] == "slice_mode":
            #logger.debug(f"Slice mode changing from: {cfg.retrieval_mode}")
            if cfg.retrieval_mode != "slice":
                cfg.local_sv = True
                _switch_to_slice_mode_and_jump()
            else:
                try:
                    #logger.debug(f"In slice mode changing to volume mode {viewer.layers}")
                    cfg.retrieval_mode = "volume"
                    cfg.local_sv = True
                    for _ in range(len(viewer.layers)):
                        viewer.layers.pop(0)
                    view_feature(viewer, {"feature_id": cfg.current_feature_name})
                except KeyError as e:
                    print(e)
        elif msg["data"] == "refesh_annotations":
            refresh_annotations_in_viewer(msg)
        elif msg["data"] == "paint_annotations":
            paint_annotations(msg)
        elif msg["data"] == "update_annotations":
            update_annotations(msg)
        elif msg["data"] == "remove_layer":
            layer_name = msg["layer_name"]
            remove_layer(viewer, layer_name)
        elif msg["data"] == "view_feature":
            view_feature(viewer, msg)
        elif msg["data"] == "view_pipeline":
            if msg["source"] == 'analyzer':
                view_pipeline(viewer, msg, analyzers=True)
            else:
                view_pipeline(viewer, msg)
        elif msg["data"] == "view_regions":
            view_regions(viewer, msg)
        elif msg["data"] == "view_objects":
            view_objects(viewer, msg)
        elif msg["data"] == "view_patches":
            view_patches(msg)
        elif msg["data"] == "show_roi":
            show_roi(msg)
        elif msg["data"] == "run_workflow":
            run_workflow_worker = run_workflow(msg)
            run_workflow_worker.start()
            processEvents({"data": "refresh"})
        elif msg["data"] == "refresh":
            logger.debug("Refreshing plugin panel")
            dw.ppw.setup()
        elif msg["data"] == "empty_viewer":
            logger.debug("\n\nEmptying viewer")
            for l in viewer.layers:
                viewer.layers.remove(l)
            cfg.current_feature_name = "001_raw"
            cfg.current_annotation_name = None
            cfg.current_pipeline_name = None
            cfg.current_regions_name = None
            cfg.current_analyzers_name = None

        elif msg["data"] == "save_annotation":
            save_annotation(msg)
        elif msg["data"] == "set_paint_params":
            set_paint_params(msg)
        elif msg["data"] == "set_session":
            set_session(msg)
        elif msg["data"] == "set_workspace":
            set_workspace(msg)
        elif msg["data"] == "get_crop":
            get_crop(msg)
        elif msg["data"] == "make_roi_ws":
            make_roi_ws(msg)
        elif msg["data"] == "transfer_layer":
            transfer_layer(msg)

    def _switch_to_slice_mode_and_jump():
        cfg.retrieval_mode = "slice"
        viewer_order = viewer.window.qt_viewer.viewer.dims.order
        for l in viewer.layers:
            viewer.layers.remove(l)
        
        if len(viewer_order) == 3:
            cfg.order = [int(d) for d in viewer_order]
            #logger.debug(f"Setting order to {cfg.order}")
        else:
            cfg.order = [0, 1, 2]
            #logger.debug(f"Viewer order {viewer_order} Resetting order to {cfg.order}")
        cfg.slice_max = cfg.base_dataset_shape[cfg.order[0]]
        #logger.debug(f"Setting slice max to {cfg.slice_max}")
        view_feature(viewer, {"feature_id": cfg.current_feature_name})
        try:
            jump_to_slice({"frame": 0})
        except AttributeError as e:
            print(e)
    dw.ppw.clientEvent.connect(lambda x: processEvents(x))
    cfg.ppw = dw.ppw
    cfg.processEvents = processEvents
    cfg.viewer = viewer
    dw.Config = Config
    dw.cfg = cfg
    return dw
Пример #3
0
import os.path as op
import numpy as np

from survos2.model import Workspace, Dataset

wspath = 'test_survos_datamodel'
if Workspace.exists(wspath):
    Workspace.remove(wspath)
workspace = Workspace.create(wspath)

print("Generating data")
data = np.random.rand(300, 500, 500).astype(np.float32)
print("Adding data to workspace")
ds = workspace.add_data(data)

print("Creating datasets")
f1 = workspace.add_dataset('features/tv1', 'uint8')
l1 = workspace.add_dataset('annotations/level1', np.float32)
l2 = workspace.add_dataset('annotations/level2', '|i1')

s1 = workspace.add_session('imanol')
f2 = workspace.add_dataset('features/gauss', np.float32, session='imanol')

print("Showing some data")

print(data[50])
print(f1[50])
print(l1[50])
print(l2[50])

print("Populating L1")
Пример #4
0
def get(workspace: String):
    workspace, session = parse_workspace(workspace)
    if Workspace.exists(workspace):
        return Workspace(workspace)
    raise APIException('Workspace \'%s\' does not exist.' % workspace)
Пример #5
0
def delete(workspace: String):
    workspace, session = parse_workspace(workspace)
    Workspace.remove(workspace)
    return dict(done=True)
Пример #6
0
def create(workspace: String):
    workspace, session = parse_workspace(workspace)
    return Workspace.create(workspace)