Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make "Registering of All Segments for a BBox"- feature mag aware #8082

Merged
merged 12 commits into from
Sep 19, 2024
1 change: 1 addition & 0 deletions CHANGELOG.unreleased.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ For upgrade instructions, please check the [migration guide](MIGRATIONS.released
- It is now possible to focus a bounding box in the bounding box tab by clicking its edges in a viewport or via a newly added context menu entry. [#8054](https://github.com/scalableminds/webknossos/pull/8054)
- Added the option to export nd datasets as ome tiff or tiff stack. Previously, this was only possible for 3d datasets. [#7971](https://github.com/scalableminds/webknossos/pull/7971)
- Added an assertion to the backend to ensure unique keys in the metadata info of datasets and folders. [#8068](https://github.com/scalableminds/webknossos/issues/8068)
- The feature to register all segments within a bounding box now takes the current magnification into consideration, e.g. for calculating the volume limit for a bounding box. [#8082](https://github.com/scalableminds/webknossos/pull/8082)

### Changed
- Clicking on a bounding box within the bounding box tab centers it within the viewports and focusses it in the list. [#8049](https://github.com/scalableminds/webknossos/pull/8049)
Expand Down
70 changes: 46 additions & 24 deletions frontend/javascripts/oxalis/api/api_latest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -656,35 +656,55 @@ class TracingApi {
bbName: string,
options?: { maximumSegmentCount?: number; maximumVolume?: number },
) => {
const state = Store.getState();
const maximumVolume = options?.maximumVolume ?? Constants.REGISTER_SEGMENTS_BB_MAX_VOLUME_VX;
const maximumSegmentCount =
options?.maximumSegmentCount ?? Constants.REGISTER_SEGMENTS_BB_MAX_SEGMENT_COUNT;
const shape = Utils.computeShapeFromBoundingBox({ min, max });
const volume = Math.ceil(shape[0] * shape[1] * shape[2]);

const segmentationLayerName = api.data.getVisibleSegmentationLayerName();
if (segmentationLayerName == null) {
throw new Error(
"No segmentation layer is currently visible. Enable the one you want to register segments for.",
);
}

const resolutionInfo = getResolutionInfo(
getLayerByName(state.dataset, segmentationLayerName).resolutions,
);
const theoreticalMagIndex = getActiveMagIndexForLayer(state, segmentationLayerName);
const existingMagIndex = resolutionInfo.getIndexOrClosestHigherIndex(theoreticalMagIndex);
if (existingMagIndex == null) {
throw new Error("The index of the current mag could be found.");
dieknolle3333 marked this conversation as resolved.
Show resolved Hide resolved
}
const currentMag = resolutionInfo.getResolutionByIndex(existingMagIndex);
if (currentMag == null) {
throw new Error("No mag could be found.");
}

const volume =
Math.ceil(shape[0] / currentMag[0]) *
Math.ceil(shape[1] / currentMag[1]) *
Math.ceil(shape[2] / currentMag[2]);
if (volume > maximumVolume) {
Toast.error(
`The volume of the bounding box exceeds ${maximumVolume} Vx, please make it smaller.`,
throw new Error(
`The volume of the bounding box exceeds ${maximumVolume} vx, please make it smaller. Currently, the bounding box has a volume of ${volume} vx in the active resolution (${currentMag.join("-")}).`,
);
return;
} else if (volume > maximumVolume / 8) {
Toast.warning(
"The volume of the bounding box is very large, registering all segments might take a while.",
);
}

const segmentationLayerName = api.data.getSegmentationLayerNames()[0];
const layer = getLayerByName(Store.getState().dataset, segmentationLayerName);

const resolutionInfo = getResolutionInfo(layer.resolutions);
const finestResolution = resolutionInfo.getFinestResolution();
// By default, getDataForBoundingBox uses the finest existing magnification.
// We use that as strides to traverse the data array properly.
const [dx, dy, dz] = finestResolution;

const data = await api.data.getDataForBoundingBox(segmentationLayerName, {
min,
max,
});
const data = await api.data.getDataForBoundingBox(
segmentationLayerName,
{
min,
max,
},
existingMagIndex,
);
const [dx, dy, dz] = currentMag;

const segmentIdToPosition = new Map();
let idx = 0;
Expand All @@ -703,21 +723,23 @@ class TracingApi {
const segmentIdCount = Array.from(segmentIdToPosition.entries()).length;
const halfMaxNoSegments = maximumSegmentCount / 2;
if (segmentIdCount > maximumSegmentCount) {
Toast.error(
throw new Error(
`The given bounding box contains ${segmentIdCount} segments, but only ${maximumSegmentCount} segments can be registered at once. Please reduce the size of the bounding box.`,
);
return;
} else if (segmentIdCount > halfMaxNoSegments) {
Toast.warning(
`The bounding box contains more than ${halfMaxNoSegments} segments. Registering all segments might take a while.`,
);
}

const groupId = api.tracing.createSegmentGroup(
`Segments for ${bbName}`,
-1,
segmentationLayerName,
);
let groupId = MISSING_GROUP_ID;
try {
groupId = api.tracing.createSegmentGroup(`Segments for ${bbName}`, -1, segmentationLayerName);
} catch (_e) {
console.info(
`Volume tracing could not be found for the currently visible segmentation layer, registering segments for ${bbName} within root group.`,
);
}
const updateSegmentActions: BatchableUpdateSegmentAction[] = [];
for (const [segmentId, position] of segmentIdToPosition.entries()) {
api.tracing.registerSegment(segmentId, position, undefined, segmentationLayerName);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ import type { OxalisState } from "oxalis/store";
import type { APISegmentationLayer } from "types/api_flow_types";
import { api } from "oxalis/singletons";
import FastTooltip from "components/fast_tooltip";
import Toast from "libs/toast";
import { handleGenericError } from "libs/error_handling";

const ROW_GUTTER = 1;

Expand Down Expand Up @@ -488,7 +490,9 @@ class UserBoundingBoxInput extends React.PureComponent<UserBoundingBoxInputProps
onRegisterSegmentsForBB(value: Vector6, name: string): void {
const min: Vector3 = [value[0], value[1], value[2]];
const max: Vector3 = [value[0] + value[3], value[1] + value[4], value[2] + value[5]];
api.tracing.registerSegmentsForBoundingBox(min, max, name);
api.tracing
.registerSegmentsForBoundingBox(min, max, name)
.catch((error) => Toast.error(error.message));
this.maybeCloseContextMenu();
}

Expand Down