Пример #1
0
def test_data_roi_get_tiles_can_clamp_to_datasource_tiles():
    # fmt: off
    data = Array5D(np.asarray([
        [1, 2, 3, 4, 5],
        [6, 7, 8, 9, 10],
        [11, 12, 13, 14, 15],
        [16, 17, 18, 19, 20],
    ]).astype(np.uint8),
                   axiskeys="yx")
    # fmt: on

    ds = ArrayDataSource.from_array5d(data, tile_shape=Shape5D(x=2, y=2))
    data_slice = DataRoi(datasource=ds, x=(1, 4), y=(0, 3))

    # fmt: off
    dataslice_expected_data = Array5D(np.asarray([[2, 3, 4], [7, 8, 9],
                                                  [12, 13,
                                                   14]]).astype(np.uint8),
                                      axiskeys="yx",
                                      location=Point5D.zero(x=1))
    # fmt: on

    assert data_slice.retrieve() == dataslice_expected_data

    # fmt: off
    dataslice_expected_slices = [
        Array5D(np.asarray([[1, 2], [6, 7]]).astype(np.uint8),
                axiskeys="yx",
                location=Point5D.zero()),
        Array5D(np.asarray([
            [3, 4],
            [8, 9],
        ]).astype(np.uint8),
                axiskeys="yx",
                location=Point5D.zero(x=2)),
        Array5D(np.asarray([
            [11, 12],
            [16, 17],
        ]).astype(np.uint8),
                axiskeys="yx",
                location=Point5D.zero(y=2)),
        Array5D(np.asarray([
            [13, 14],
            [18, 19],
        ]).astype(np.uint8),
                axiskeys="yx",
                location=Point5D.zero(x=2, y=2))
    ]
    # fmt: on
    expected_slice_dict = {a.interval: a for a in dataslice_expected_slices}
    for piece in data_slice.get_datasource_tiles(clamp_to_datasource=True):
        expected_data = expected_slice_dict.pop(piece.interval)
        assert expected_data == piece.retrieve()
    assert len(expected_slice_dict) == 0
Пример #2
0
    def compute(self, roi: DataRoi) -> ConnectedComponents:
        roi = roi.updated(c=self.object_channel_idx)
        expansion_step: Shape5D = (self.expansion_step or roi.tile_shape).updated(c=0)

        current_roi = roi
        while True:
            thresholded_data: ScalarData = ScalarData.fromArray5D(self.preprocessor.compute(current_roi))
            connected_comps = ConnectedComponents.label(thresholded_data)
            if connected_comps.fully_contains_objects_in(roi):
                break
            if current_roi == roi.full():
                break
            # FIXME: check mximum_tile_size too
            current_roi = current_roi.enlarged(radius=expansion_step).clamped(roi.full())
        return connected_comps.clean(roi)
Пример #3
0
def test_distributed_n5_datasink():
    tmp_path = create_tmp_dir(prefix="test_distributed_n5_datasink")
    filesystem = OsFs(tmp_path.as_posix())
    outer_path = PurePosixPath("test_distributed_n5_datasink.n5")
    inner_path = PurePosixPath("/data")
    full_path = PurePosixPath("test_distributed_n5_datasink.n5/data")
    attributes = N5DatasetAttributes(
        dimensions=datasource.shape,
        blockSize=datasource.tile_shape,
        c_axiskeys=data.axiskeys,  #FIXME: double check this
        dataType=datasource.dtype,
        compression=RawCompressor())
    sink = N5DatasetSink(outer_path=outer_path,
                         inner_path=inner_path,
                         filesystem=filesystem,
                         attributes=attributes)
    sink_writer = sink.create()
    assert not isinstance(sink_writer, Exception)
    sink_writers = [sink_writer] * 4

    for idx, piece in enumerate(DataRoi(datasource).default_split()):
        sink = sink_writers[idx % len(sink_writers)]
        sink.write(piece.retrieve())

    n5ds = N5DataSource(filesystem=filesystem, path=full_path)
    assert n5ds.retrieve() == data
Пример #4
0
    def compute(self, roi: DataRoi) -> ScalarData:
        raw_data = roi.retrieve().raw(Point5D.LABELS)
        out = ScalarData.allocate(interval=roi, dtype=np.dtype("bool"))

        out.raw(Point5D.LABELS)[raw_data >= self.threshold] = True
        out.raw(Point5D.LABELS)[raw_data < self.threshold] = False
        return out
Пример #5
0
def test_distributed_n5_datasink(tmp_path: Path, data: Array5D,
                                 datasource: DataSource):
    filesystem = OsFs(tmp_path.as_posix())
    outer_path = Path("test_distributed_n5_datasink.n5")
    inner_path = PurePosixPath("/data")
    full_path = Path("test_distributed_n5_datasink.n5/data")
    attributes = N5DatasetAttributes(dimensions=datasource.shape,
                                     blockSize=datasource.tile_shape,
                                     axiskeys=datasource.axiskeys,
                                     dataType=datasource.dtype,
                                     compression=RawCompressor())
    sinks = [
        N5DatasetSink.create(outer_path=outer_path,
                             inner_path=inner_path,
                             filesystem=filesystem,
                             attributes=attributes),
        N5DatasetSink.open(path=full_path, filesystem=filesystem),
        N5DatasetSink.open(path=full_path, filesystem=filesystem),
        N5DatasetSink.open(path=full_path, filesystem=filesystem),
    ]

    for idx, piece in enumerate(DataRoi(datasource).default_split()):
        sink = sinks[idx % len(sinks)]
        sink.write(piece.retrieve())

    n5ds = N5DataSource(filesystem=filesystem, path=full_path)
    assert n5ds.retrieve() == data
Пример #6
0
def test_neighboring_tiles():
    # fmt: off
    arr = Array5D(np.asarray(
        [[10, 11, 12, 20, 21, 22, 30], [13, 14, 15, 23, 24, 25, 33],
         [16, 17, 18, 26, 27, 28, 36], [40, 41, 42, 50, 51, 52, 60],
         [43, 44, 45, 53, 54, 55, 63], [46, 47, 48, 56, 57, 58, 66],
         [70, 71, 72, 80, 81, 82, 90], [73, 74, 75, 83, 84, 85, 93],
         [76, 77, 78, 86, 87, 88, 96], [0, 1, 2, 3, 4, 5, 6]],
        dtype=np.uint8),
                  axiskeys="yx")

    ds = SkimageDataSource(path=create_png(arr), filesystem=OsFs("/"))

    fifties_slice = DataRoi(ds, x=(3, 6), y=(3, 6))
    expected_fifties_slice = Array5D(np.asarray([[50, 51, 52], [53, 54, 55],
                                                 [56, 57, 58]]),
                                     axiskeys="yx")
    # fmt: on

    top_slice = DataRoi(ds, x=(3, 6), y=(0, 3))
    bottom_slice = DataRoi(ds, x=(3, 6), y=(6, 9))

    right_slice = DataRoi(ds, x=(6, 7), y=(3, 6))
    left_slice = DataRoi(ds, x=(0, 3), y=(3, 6))

    # fmt: off
    fifties_neighbor_data = {
        top_slice:
        Array5D(np.asarray([[20, 21, 22], [23, 24, 25], [26, 27, 28]]),
                axiskeys="yx"),
        right_slice:
        Array5D(np.asarray([[60], [63], [66]]), axiskeys="yx"),
        bottom_slice:
        Array5D(np.asarray([[80, 81, 82], [83, 84, 85], [86, 87, 88]]),
                axiskeys="yx"),
        left_slice:
        Array5D(np.asarray([[40, 41, 42], [43, 44, 45], [46, 47, 48]]),
                axiskeys="yx"),
    }

    # fmt: on

    assert (fifties_slice.retrieve().raw("yx") == expected_fifties_slice.raw(
        "yx")).all()  # type: ignore

    for neighbor in fifties_slice.get_neighboring_tiles(
            tile_shape=Shape5D(x=3, y=3)):
        try:
            expected_slice = fifties_neighbor_data.pop(neighbor)
            assert (expected_slice.raw("yx") == neighbor.retrieve().raw("yx")
                    ).all()  # type: ignore
        except KeyError:
            print(f"\nWas searching for ", neighbor, "\n")
            for k in fifties_neighbor_data.keys():
                print("--->>> ", k)
    assert len(fifties_neighbor_data) == 0
Пример #7
0
    def __call__(self, roi: DataRoi) -> FeatureData:
        haloed_roi = roi.enlarged(self.halo)
        source_data = self.preprocessor(haloed_roi)

        step_shape: Shape5D = Shape5D(
            c=1,
            t=1,
            x=1 if self.axis_2d == "x" else source_data.shape.x,
            y=1 if self.axis_2d == "y" else source_data.shape.y,
            z=1 if self.axis_2d == "z" else source_data.shape.z,
        )

        out = Array5D.allocate(
            interval=roi.updated(c=(roi.c[0] * self.channel_multiplier,
                                    roi.c[1] * self.channel_multiplier)),
            dtype=numpy.dtype("float32"),
            axiskeys=source_data.axiskeys.replace("c", "") +
            "c"  # fastfilters puts channel last
        )

        for data_slice in source_data.split(step_shape):
            source_axes = "zyx"
            if self.axis_2d:
                source_axes = source_axes.replace(self.axis_2d, "")

            raw_data: "ndarray[Any, dtype[float32]]" = data_slice.raw(
                source_axes).astype(numpy.float32)
            raw_feature_data: "ndarray[Any, dtype[float32]]" = self.filter_fn(
                raw_data)

            feature_data = FeatureData(
                raw_feature_data,
                axiskeys=source_axes +
                "c" if len(raw_feature_data.shape) > len(source_axes) else
                source_axes,
                location=data_slice.location.updated(c=data_slice.location.c *
                                                     self.channel_multiplier))
            out.set(feature_data, autocrop=True)
        out.setflags(write=False)
        return FeatureData(
            out.raw(out.axiskeys),
            axiskeys=out.axiskeys,
            location=out.location,
        )
Пример #8
0
def test_skimage_datasource_tiles(png_image: Path):
    bs = DataRoi(SkimageDataSource(png_image, filesystem=OsFs("/")))
    num_checked_tiles = 0
    for tile in bs.split(Shape5D(x=2, y=2)):
        if tile == Interval5D.zero(x=(0, 2), y=(0, 2)):
            expected_raw = raw_0_2x0_2y
        elif tile == Interval5D.zero(x=(0, 2), y=(2, 4)):
            expected_raw = raw_0_2x2_4y
        elif tile == Interval5D.zero(x=(2, 4), y=(0, 2)):
            expected_raw = raw_2_4x0_2y
        elif tile == Interval5D.zero(x=(2, 4), y=(2, 4)):
            expected_raw = raw_2_4x2_4y
        elif tile == Interval5D.zero(x=(4, 5), y=(0, 2)):
            expected_raw = raw_4_5x0_2y
        elif tile == Interval5D.zero(x=(4, 5), y=(2, 4)):
            expected_raw = raw_4_5x2_4y
        else:
            raise Exception(f"Unexpected tile {tile}")
        assert (tile.retrieve().raw("yx") == expected_raw).all()
        num_checked_tiles += 1
    assert num_checked_tiles == 6
Пример #9
0
 def __init__(
         self,
         *,
         position: Point5D,  # an anchor point within datasource
         klass: int,
         datasource: DataSource,  # an object label is tied to the datasource
         components_extractor:
     ConnectedComponentsExtractor,  # and also to the method used to extract the objects
 ):
     position_roi = DataRoi(datasource,
                            **Interval5D.enclosing([position]).to_dict())
     self.data_tile = position_roi.get_tiles(
         datasource.tile_shape,
         clamp=False).__next__().clamped(datasource.shape)
     self.position = position
     self.klass = klass
     self.datasource = datasource
     self.components_extractor = components_extractor
     # compute connected components in constructor to prevent creation of bad annotation
     self.label = components_extractor.compute(
         self.data_tile).label_at(position)
    async def precomputed_chunks_compute(self, request: web.Request) -> web.Response:
        encoded_raw_data = str(request.match_info.get("encoded_raw_data"))
        generation = int(request.match_info.get("generation")) # type: ignore
        xBegin = int(request.match_info.get("xBegin")) # type: ignore
        xEnd = int(request.match_info.get("xEnd")) # type: ignore
        yBegin = int(request.match_info.get("yBegin")) # type: ignore
        yEnd = int(request.match_info.get("yEnd")) # type: ignore
        zBegin = int(request.match_info.get("zBegin")) # type: ignore
        zEnd = int(request.match_info.get("zEnd")) # type: ignore

        datasource = _decode_datasource(encoded_raw_data)
        with self.lock:
            classifier = self.pixel_classifier()
            label_classes = self._in_label_classes()
        if classifier is None:
            return web.json_response({"error": "Classifier is not ready yet"}, status=412)

        if generation != self._state.generation:
            return web.json_response({"error": "This classifier is stale"}, status=410)

        predictions = await asyncio.wrap_future(self.executor.submit(
            classifier,
            DataRoi(datasource, x=(xBegin, xEnd), y=(yBegin, yEnd), z=(zBegin, zEnd))
        ))

        if "format" in request.query:
            requested_format = request.query["format"]
            if requested_format != "png":
                return web.Response(status=400, text=f"Server-side rendering only available in png, not in {requested_format}")
            if predictions.shape.z > 1:
                return web.Response(status=400, text="Server-side rendering only available for 2d images")

            class_colors = tuple(label_classes.keys())
            prediction_png_bytes = list(predictions.to_z_slice_pngs(class_colors))[0] #FIXME assumes shape.t=1 and shape.z=1
            return web.Response(
                body=prediction_png_bytes.getbuffer(),
                headers={
                    "Cache-Control": "no-store, must-revalidate",
                    "Expires": "0",
                },
                content_type="image/png",
            )

        # https://github.com/google/neuroglancer/tree/master/src/neuroglancer/datasource/precomputed#raw-chunk-encoding
        # "(...) data for the chunk is stored directly in little-endian binary format in [x, y, z, channel] Fortran order"
        resp = predictions.as_uint8().raw("xyzc").tobytes("F")
        return web.Response(
            body=resp,
            content_type="application/octet-stream",
        )
Пример #11
0
    async def precomputed_chunks_compute(self,
                                         request: web.Request) -> web.Response:
        encoded_raw_data = str(
            request.match_info.get("encoded_raw_data"))  # type: ignore
        xBegin = int(request.match_info.get("xBegin"))  # type: ignore
        xEnd = int(request.match_info.get("xEnd"))  # type: ignore
        yBegin = int(request.match_info.get("yBegin"))  # type: ignore
        yEnd = int(request.match_info.get("yEnd"))  # type: ignore
        zBegin = int(request.match_info.get("zBegin"))  # type: ignore
        zEnd = int(request.match_info.get("zEnd"))  # type: ignore

        datasource = _decode_datasource(encoded_raw_data)
        predictions = await self.runner.async_submit(
            self.pixel_classifier().compute,
            DataRoi(datasource,
                    x=(xBegin, xEnd),
                    y=(yBegin, yEnd),
                    z=(zBegin, zEnd)))

        if "format" in request.query:
            requested_format = request.query["format"]
            if requested_format != "png":
                return web.Response(
                    status=400,
                    text=
                    "Server-side rendering only available in png, not in {requested_format}"
                )
            if predictions.shape.z > 1:
                return web.Response(
                    status=400,
                    text="Server-side rendering only available for 2d images")

            prediction_png_bytes = list(predictions.to_z_slice_pngs())[0]
            return web.Response(
                body=prediction_png_bytes.getbuffer(),
                headers={
                    "Cache-Control": "no-store, must-revalidate",
                    "Expires": "0",
                },
                content_type="image/png",
            )

        # https://github.com/google/neuroglancer/tree/master/src/neuroglancer/datasource/precomputed#raw-chunk-encoding
        # "(...) data for the chunk is stored directly in little-endian binary format in [x, y, z, channel] Fortran order"
        resp = predictions.as_uint8().raw("xyzc").tobytes("F")
        return web.Response(
            body=resp,
            content_type="application/octet-stream",
        )
Пример #12
0
    def compute(self, roi: DataRoi) -> FeatureData:
        roi_step: Shape5D = roi.shape.updated(
            c=1, t=1)  # compute features independently for each c and each t
        if self.axis_2d:
            roi_step = roi_step.updated(**{self.axis_2d:
                                           1})  # also compute in 2D slices

        per_channel_results: List[FeatureData] = []
        for roi_slice in roi.split(roi_step):
            haloed_roi = roi_slice.enlarged(self.halo)
            channel_offset = roi_slice.start.c - roi.start.c
            if self.presmooth_sigma > 0:
                gaussian_filter = GaussianSmoothing(
                    preprocessor=self.preprocessor,
                    sigma=self.presmooth_sigma,
                    axis_2d=self.axis_2d,
                    window_size=3.5)
                source_data = gaussian_filter.compute(haloed_roi)
            else:
                source_data = self.preprocessor.compute(haloed_roi)

            source_axes = "zyx"
            if self.axis_2d:
                source_axes = source_axes.replace(self.axis_2d, "")

            raw_data: numpy.ndarray = source_data.raw(source_axes).astype(
                numpy.float32)
            raw_feature_data: numpy.ndarray = self.filter_fn(raw_data)
            if len(raw_feature_data.shape) > len(source_axes):
                output_axes = source_axes + "c"
                channel_multiplier = raw_feature_data.shape[-1]
            else:
                output_axes = source_axes
                channel_multiplier = 1
            feature_data = FeatureData(
                raw_feature_data,
                axiskeys=output_axes,
                location=haloed_roi.start.updated(c=channel_offset *
                                                  channel_multiplier))
            per_channel_results.append(feature_data.cut(roi_slice, c=All()))
        combined_result = Array5D.combine(per_channel_results)
        out = FeatureData(combined_result.raw(combined_result.axiskeys),
                          axiskeys=combined_result.axiskeys,
                          location=combined_result.location)
        out.setflags(write=False)
        return out
Пример #13
0
def test_n5_datasink(tmp_path: Path, data: Array5D, datasource: DataSource):
    sink = N5DatasetSink.create(filesystem=OsFs(tmp_path.as_posix()),
                                outer_path=Path("test_n5_datasink.n5"),
                                inner_path=PurePosixPath("/data"),
                                attributes=N5DatasetAttributes(
                                    dimensions=datasource.shape,
                                    blockSize=Shape5D(x=10, y=10),
                                    axiskeys=datasource.axiskeys,
                                    dataType=datasource.dtype,
                                    compression=RawCompressor(),
                                    location=Point5D.zero(x=7, y=13)))
    for tile in DataRoi(datasource).split(sink.tile_shape):
        sink.write(tile.retrieve().translated(Point5D.zero(x=7, y=13)))

    n5ds = N5DataSource(filesystem=sink.filesystem, path=sink.path)
    saved_data = n5ds.retrieve()
    assert saved_data.location == Point5D.zero(x=7, y=13)
    assert saved_data == data
Пример #14
0
def test_n5_datasink():
    tmp_path = create_tmp_dir(prefix="test_n5_datasink")
    sink = N5DatasetSink(
        filesystem=OsFs(tmp_path.as_posix()),
        outer_path=PurePosixPath("test_n5_datasink.n5"),
        inner_path=PurePosixPath("/data"),
        attributes=N5DatasetAttributes(
            dimensions=datasource.shape,
            blockSize=Shape5D(x=10, y=10),
            c_axiskeys=data.axiskeys,  #FIXME: double check this
            dataType=datasource.dtype,
            compression=RawCompressor(),
            location=Point5D.zero(x=7, y=13)))
    sink_writer = sink.create()
    assert not isinstance(sink_writer, Exception)
    for tile in DataRoi(datasource).split(sink.tile_shape):
        sink_writer.write(tile.retrieve().translated(Point5D.zero(x=7, y=13)))

    n5ds = N5DataSource(filesystem=sink.filesystem, path=sink.full_path)
    saved_data = n5ds.retrieve()
    assert saved_data.location == Point5D.zero(x=7, y=13)
    assert saved_data == data
Пример #15
0
 def compute(self, roi: DataRoi) -> Array5D:
     return roi.retrieve()
Пример #16
0
 def draw(self, operator: Operator[DataRoi, Array5D],
          datasource: DataSource):
     data = operator.compute(DataRoi(datasource))
     data.show_channels()
Пример #17
0
def test_pixel_classification_workflow():
    brushing_applet = BrushingApplet("brushing_applet")
    feature_selection_applet = FeatureSelectionApplet(
        "feature_selection_applet", datasources=brushing_applet.datasources)
    pixel_classifier_applet = PixelClassificationApplet(
        "pixel_classifier_applet",
        feature_extractors=feature_selection_applet.feature_extractors,
        annotations=brushing_applet.annotations)
    # wf = PixelClassificationWorkflow(
    #     feature_selection_applet=feature_selection_applet,
    #     brushing_applet=brushing_applet,
    #     pixel_classifier_applet=pixel_classifier_applet,
    #     predictions_export_applet=predictions_export_applet
    # )

    # GUI creates a datasource somewhere...
    ds = SkimageDataSource(Path("public/images/c_cells_1.png"),
                           filesystem=OsFs("."),
                           tile_shape=Shape5D(x=400, y=400))

    # GUI creates some feature extractors
    feature_selection_applet.feature_extractors.set_value(
        [
            GaussianSmoothing.from_ilp_scale(scale=0.3, axis_2d="z"),
            HessianOfGaussianEigenvalues.from_ilp_scale(scale=0.7,
                                                        axis_2d="z"),
        ],
        confirmer=dummy_confirmer)

    # GUI creates some annotations
    brush_strokes = [
        Annotation.interpolate_from_points(
            voxels=[Point5D.zero(x=140, y=150),
                    Point5D.zero(x=145, y=155)],
            color=Color(r=np.uint8(0), g=np.uint8(0), b=np.uint8(255)),
            raw_data=ds),
        Annotation.interpolate_from_points(
            voxels=[Point5D.zero(x=238, y=101),
                    Point5D.zero(x=229, y=139)],
            color=Color(r=np.uint8(0), g=np.uint8(0), b=np.uint8(255)),
            raw_data=ds),
        Annotation.interpolate_from_points(
            voxels=[Point5D.zero(x=283, y=87),
                    Point5D.zero(x=288, y=92)],
            color=Color(r=np.uint8(255), g=np.uint8(0), b=np.uint8(0)),
            raw_data=ds),
        Annotation.interpolate_from_points(
            voxels=[Point5D.zero(x=274, y=168),
                    Point5D.zero(x=256, y=191)],
            color=Color(r=np.uint8(255), g=np.uint8(0), b=np.uint8(0)),
            raw_data=ds),
    ]
    brushing_applet.annotations.set_value(brush_strokes,
                                          confirmer=dummy_confirmer)

    # preds = predictions_export_applet.compute(DataRoi(ds))

    classifier = pixel_classifier_applet.pixel_classifier()
    executor = HashingExecutor(num_workers=8)

    # calculate predictions on an arbitrary data
    preds = executor.submit(classifier.compute, ds.roi)
    preds.result().as_uint8().show_channels()

    # for png_bytes in preds.to_z_slice_pngs():
    #     path = f"/tmp/junk_test_image_{uuid.uuid4()}.png"
    #     with open(path, "wb") as outfile:
    #         outfile.write(png_bytes.getbuffer())
    #     os.system(f"gimp {path}")

    # calculate predictions on just a piece of arbitrary data
    exported_tile = executor.submit(
        classifier.compute, DataRoi(datasource=ds, x=(100, 200), y=(100, 200)))
    exported_tile.result().show_channels()

    # wf.save_as(Path("/tmp/blas.ilp"))

    #try removing a brush stroke
    brushing_applet.annotations.set_value(brush_strokes[1:],
                                          confirmer=dummy_confirmer)
    assert tuple(brushing_applet.annotations()) == tuple(brush_strokes[1:])
Пример #18
0
def _write_data(tile: DataRoi, sink_writer: DataSinkWriter):
    print(f"Writing {tile}")
    sink_writer.write(tile.retrieve())