Skip to content
This repository has been archived by the owner on May 31, 2023. It is now read-only.

Incorrect largest segment ID for Neuroglancer segmentation layer #92

Closed
cnzqy1 opened this issue May 27, 2020 · 1 comment · Fixed by #101
Closed

Incorrect largest segment ID for Neuroglancer segmentation layer #92

cnzqy1 opened this issue May 27, 2020 · 1 comment · Fixed by #101
Assignees

Comments

@cnzqy1
Copy link

cnzqy1 commented May 27, 2020

The largest segment ID for Neuroglancer segmentation layer defaults to 2^32-1 (4294967295) and cannot be changed. If it is difficult to automatically detect the largest segment ID, allowing this field to be manually edited would be helpful.

@cnzqy1
Copy link
Author

cnzqy1 commented Jun 12, 2020

This issue blocked something we wanted to do, so I made a quick fix myself:

In wkconnect/backends/neuroglancer/models.py, replace the class Layer with the following:

@dataclass(frozen=True)
class Layer:
    source: str
    data_type: str
    num_channels: int
    scales: Tuple[Scale, ...]
    relative_scale: Vec3D
    type: str
    largestSegmentId: Optional[int] = field(default=None)
    # InitVar allows to consume mesh argument in init without storing it
    mesh: InitVar[Any] = None

    def __post_init__(self, mesh: Any) -> None:
        supported_data_types = {
            "image": ["uint8", "uint16", "uint32", "uint64"],
            "segmentation": ["uint32", "uint64"],
        }
        assert self.type in supported_data_types
        assert self.data_type in supported_data_types[self.type]
        assert self.num_channels == 1
        assert all(
            max(scale.resolution) == 2 ** i for i, scale in enumerate(self.scales)
        )

    def wk_data_type(self) -> str:
        if self.type == "segmentation":
            return "uint32"
        return self.data_type

    def to_webknossos(self, layer_name: str) -> WkDataLayer:
        return WkDataLayer(
            layer_name,
            {"image": "color", "segmentation": "segmentation"}[self.type],
            self.scales[0].bounding_box(),
            [scale.resolution for scale in self.scales],
            self.wk_data_type(),
            self.largestSegmentId
        )

And in wkconnect/webknossos/models.py, replace the class DataLayer with the following:

@dataclass(unsafe_hash=True)
class DataLayer:
    name: str
    category: str
    boundingBox: BoundingBox
    resolutions: List[Vec3D]
    elementClass: str
    largestSegmentId: Optional[int] = field(default=None)
    dataFormat: str = field(default="wkw", init=False)
    wkwResolutions: JSON = field(init=False)
    mappings: Optional[List[Any]] = field(default=None, init=False)

    def __post_init__(self) -> None:
        assert self.category in ["color", "segmentation"]
        assert self.elementClass in ["uint8", "uint16", "uint32", "uint64"]
        if self.category == "segmentation":
            self.mappings = []
            if self.largestSegmentId is None:
                self.largestSegmentId = cast(int, np.iinfo(self.elementClass).max)
        self.wkwResolutions = [
            {"resolution": i, "cubeLength": 1024} for i in self.resolutions
        ]

After these modifications, in data/datasets.json "largestSegmentId": (some integer) can then be specified for the segmentation layer and read by webKnossos. This might break BossDB connectivity but I haven't tested it.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants