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

Proofreading without skeletons #6625

Merged
merged 20 commits into from
Nov 21, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
3745863
first PoC
daniel-wer Oct 18, 2022
6b9204d
Merge branch 'master' of github.com:scalableminds/webknossos into pro…
daniel-wer Oct 18, 2022
4a9fd59
use activeCellId for proofreading
daniel-wer Oct 18, 2022
b37134e
prototype active segment pulsing
daniel-wer Oct 25, 2022
1b69c96
Revert "prototype active segment pulsing"
daniel-wer Oct 27, 2022
d625a3d
Merge branch 'master' of github.com:scalableminds/webknossos into pro…
daniel-wer Nov 9, 2022
e1f37b0
show cross hair for active segment position in proofreading mode and …
daniel-wer Nov 9, 2022
c594312
renaming
daniel-wer Nov 9, 2022
08753ec
clean up and remove agglomerate skeletons from proofreading saga
daniel-wer Nov 9, 2022
106969c
allow to select node in proofreading mode and dispatch proofreading a…
daniel-wer Nov 10, 2022
988a718
Merge branch 'master' of github.com:scalableminds/webknossos into pro…
daniel-wer Nov 14, 2022
884ed1b
remove passive meshes, refactor cross hair shader
daniel-wer Nov 14, 2022
ee66fca
fix superfluous passive flag
daniel-wer Nov 14, 2022
adefbd7
fix that the cursor never changed again after activating the bounding…
daniel-wer Nov 14, 2022
ad673cc
add shift and ctrl modifiers to proofreading tool for faster actions
daniel-wer Nov 14, 2022
8e34629
include shortcuts in context menu
daniel-wer Nov 14, 2022
343b6e0
update changelog
daniel-wer Nov 15, 2022
93af3fa
Merge branch 'master' of github.com:scalableminds/webknossos into pro…
daniel-wer Nov 16, 2022
1f1c6b6
apply PR feedback and clean up at 0,0,0
daniel-wer Nov 16, 2022
14b8719
Merge branch 'master' into proofreading-without-skeletons
daniel-wer Nov 21, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.unreleased.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ For upgrade instructions, please check the [migration guide](MIGRATIONS.released
- Re-phrased some backend (error) messages to improve clarity and provide helping hints. [#6616](https://github.com/scalableminds/webknossos/pull/6616)
- The layer visibility is now encoded in the sharing link. The user opening the link will see the same layers that were visible when copying the link. [#6634](https://github.com/scalableminds/webknossos/pull/6634)
- Voxelytics workflows can now be viewed by anyone with the link who is in the right organization. [#6622](https://github.com/scalableminds/webknossos/pull/6622)
- Reworked the proofreading mode so that agglomerate skeletons are no longer needed (nor automatically loaded). Instead, segments can be selected by left-clicking onto them, indicated by a small white cross. To merge or split agglomerates, then either use the shortcuts `Shift + Leftclick`/`Ctrl + Leftclick` or use the context menu. [#6625](https://github.com/scalableminds/webknossos/pull/6625)

### Fixed
- Fixed a bug in the dataset import view, where the layer name text field would lose focus after each key press. [#6615](https://github.com/scalableminds/webknossos/pull/6615)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,8 @@ export function getClosestHoveredBoundingBox(
export const highlightAndSetCursorOnHoveredBoundingBox = _.throttle(
(delta: Point2, position: Point2, planeId: OrthoView) => {
const hoveredEdgesInfo = getClosestHoveredBoundingBox(position, planeId);
const inputCatcher = document.getElementById(`inputcatcher_${planeId}`);
// Access the parent element as that is where the cursor style property is set
const inputCatcher = document.getElementById(`inputcatcher_${planeId}`)?.parentElement;
daniel-wer marked this conversation as resolved.
Show resolved Hide resolved

if (hoveredEdgesInfo != null && inputCatcher != null) {
const [primaryHoveredEdge, secondaryHoveredEdge] = hoveredEdgesInfo;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,11 @@ import * as Utils from "libs/utils";
import * as VolumeHandlers from "oxalis/controller/combinations/volume_handlers";
import { document } from "libs/window";
import api from "oxalis/api/internal_api";
import { proofreadAtPosition } from "oxalis/model/actions/proofread_actions";
import {
minCutAgglomerateWithPositionAction,
proofreadAtPosition,
proofreadMerge,
} from "oxalis/model/actions/proofread_actions";
import { calculateGlobalPos } from "oxalis/model/accessors/view_mode_accessor";
import { V3 } from "libs/mjs";

Expand Down Expand Up @@ -690,13 +694,13 @@ export class QuickSelectTool {
_delta: Point2,
pos: Point2,
_id: string | null | undefined,
_event: MouseEvent,
event: MouseEvent,
) => {
if (!isDragging || startPos == null) {
return;
}
const newCurrentPos = V3.floor(calculateGlobalPos(Store.getState(), pos));
if (_event.shiftKey) {
if (event.shiftKey) {
// If shift is held, the rectangle is resized on topLeft and bottomRight
// so that the center is constant.
// We don't use the passed _delta variable, because that is given in pixel-space
Expand Down Expand Up @@ -751,37 +755,47 @@ export class ProofreadTool {
}

static onLeftClick(
planeView: PlaneView,
_planeView: PlaneView,
pos: Point2,
plane: OrthoView,
_event: MouseEvent,
isTouch: boolean,
event: MouseEvent,
_isTouch: boolean,
) {
const didSelectNode = SkeletonHandlers.handleSelectNode(planeView, pos, plane, isTouch);
if (didSelectNode) {
// Don't do anything else
return;
}
daniel-wer marked this conversation as resolved.
Show resolved Hide resolved

if (plane === OrthoViews.TDView) {
// The click position cannot be mapped to a 3D coordinate in the
// 3D viewport (unless a node was clicked which is already handled above).
// 3D viewport.
return;
}

const globalPosition = calculateGlobalPos(Store.getState(), pos);
Store.dispatch(proofreadAtPosition(globalPosition));

if (event.shiftKey) {
Store.dispatch(proofreadMerge(globalPosition));
} else if (event.ctrlKey) {
Store.dispatch(minCutAgglomerateWithPositionAction(globalPosition));
} else {
Store.dispatch(proofreadAtPosition(globalPosition));
VolumeHandlers.handlePickCell(pos);
}
}

static getActionDescriptors(
_activeTool: AnnotationTool,
_useLegacyBindings: boolean,
_shiftKey: boolean,
_ctrlKey: boolean,
shiftKey: boolean,
ctrlKey: boolean,
_altKey: boolean,
): ActionDescriptor {
let leftClick = "Select Segment to Proofread";
daniel-wer marked this conversation as resolved.
Show resolved Hide resolved

if (shiftKey) {
leftClick = "Merge with active Segment";
} else if (ctrlKey) {
leftClick = "Split from active Segment";
}

return {
leftClick: "Select Segment to Proofread",
leftClick,
rightClick: "Context Menu",
};
}
Expand Down
23 changes: 6 additions & 17 deletions frontend/javascripts/oxalis/controller/scene_controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ class SceneController {
return color;
}

constructIsosurfaceMesh(cellId: number, geometry: THREE.BufferGeometry, passive: boolean) {
constructIsosurfaceMesh(cellId: number, geometry: THREE.BufferGeometry) {
const color = this.getColorObjectForSegment(cellId);
const meshMaterial = new THREE.MeshLambertMaterial({
color,
Expand All @@ -213,14 +213,13 @@ class SceneController {
const mesh = new THREE.Mesh(geometry, meshMaterial);
mesh.castShadow = true;
mesh.receiveShadow = true;
mesh.renderOrder = passive ? 1 : 0;
const tweenAnimation = new TWEEN.Tween({
opacity: 0,
});
tweenAnimation
.to(
{
opacity: passive ? 0.4 : 1,
opacity: 1,
},
500,
)
Expand All @@ -245,33 +244,25 @@ class SceneController {

const meshNumber = _.size(this.stlMeshes);

const mesh = this.constructIsosurfaceMesh(meshNumber, geometry, false);
const mesh = this.constructIsosurfaceMesh(meshNumber, geometry);
this.meshesRootGroup.add(mesh);
this.stlMeshes[id] = mesh;
this.updateMeshPostion(id, position);
}

addIsosurfaceFromVertices(
vertices: Float32Array,
segmentationId: number,
// Passive isosurfaces are ignored during picking, are shown more transparently, and are rendered
// last so that all non-passive isosurfaces are rendered before them. This makes sure that non-passive
// isosurfaces are not skipped during rendering if they are overlapped by passive ones.
passive: boolean,
): void {
addIsosurfaceFromVertices(vertices: Float32Array, segmentationId: number): void {
let bufferGeometry = new THREE.BufferGeometry();
bufferGeometry.setAttribute("position", new THREE.BufferAttribute(vertices, 3));

bufferGeometry = mergeVertices(bufferGeometry);
bufferGeometry.computeVertexNormals();

this.addIsosurfaceFromGeometry(bufferGeometry, segmentationId, passive);
this.addIsosurfaceFromGeometry(bufferGeometry, segmentationId);
}

addIsosurfaceFromGeometry(
geometry: THREE.BufferGeometry,
segmentationId: number,
passive: boolean = false,
offset: Vector3 | null = null,
scale: Vector3 | null = null,
): void {
Expand All @@ -281,13 +272,11 @@ class SceneController {
this.isosurfacesRootGroup.add(newGroup);
// @ts-ignore
newGroup.cellId = segmentationId;
// @ts-ignore
newGroup.passive = passive;
if (scale != null) {
newGroup.scale.copy(new THREE.Vector3(...scale));
}
}
const mesh = this.constructIsosurfaceMesh(segmentationId, geometry, passive);
const mesh = this.constructIsosurfaceMesh(segmentationId, geometry);
if (offset) {
mesh.translateX(offset[0]);
mesh.translateY(offset[1]);
Expand Down
12 changes: 12 additions & 0 deletions frontend/javascripts/oxalis/geometries/helper_geometries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ export class QuickSelectGeometry {
opacity: 0.5,
});
this.rectangle = new THREE.Mesh(geometry, material);
this.rectangle.visible = false;

const centerGeometry = new THREE.PlaneGeometry(2, 2);
const centerMaterial = new THREE.MeshBasicMaterial({
Expand All @@ -97,6 +98,7 @@ export class QuickSelectGeometry {
opacity: 0.9,
});
this.centerMarker = new THREE.Mesh(centerGeometry, centerMaterial);
this.centerMarker.visible = false;

this.meshGroup = new THREE.Group();
this.meshGroup.add(this.rectangle);
Expand Down Expand Up @@ -144,6 +146,16 @@ export class QuickSelectGeometry {

this.centerMarker.position.set(...centerPosition);

// Hide the objects if the rectangle has size zero, so whenever
// the quick select tool is not currently used to draw a rectangle.
if (V3.isEqual(endPosition, startPosition)) {
this.centerMarker.visible = false;
this.rectangle.visible = false;
} else {
this.centerMarker.visible = true;
this.rectangle.visible = true;
}

app.vent.trigger("rerender");
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
import * as THREE from "three";
import _ from "lodash";
import type { OrthoView, Vector3 } from "oxalis/constants";
import { ViewModeValues, OrthoViewValues, OrthoViews, MappingStatusEnum } from "oxalis/constants";
import {
ViewModeValues,
OrthoViewValues,
OrthoViews,
MappingStatusEnum,
AnnotationToolEnum,
} from "oxalis/constants";
import { calculateGlobalPos } from "oxalis/model/accessors/view_mode_accessor";
import { isBrushTool } from "oxalis/model/accessors/tool_accessor";
import {
getActiveCellId,
getActiveSegmentationTracing,
getActiveSegmentPosition,
} from "oxalis/model/accessors/volumetracing_accessor";
import {
getAddressSpaceDimensions,
Expand Down Expand Up @@ -148,6 +155,9 @@ class PlaneMaterialFactory {
globalMousePosition: {
value: new THREE.Vector3(0, 0, 0),
},
activeSegmentPosition: {
value: new THREE.Vector3(-1, -1, -1),
},
brushSizeInPixel: {
value: 0,
},
Expand All @@ -163,6 +173,9 @@ class PlaneMaterialFactory {
showBrush: {
value: false,
},
isProofreading: {
value: false,
},
viewMode: {
value: 0,
},
Expand Down Expand Up @@ -588,6 +601,20 @@ class PlaneMaterialFactory {
(storeState) => storeState.uiInformation.activeTool,
(annotationTool) => {
this.uniforms.showBrush.value = isBrushTool(annotationTool);
this.uniforms.isProofreading.value = annotationTool === AnnotationToolEnum.PROOFREAD;
},
true,
),
);
this.storePropertyUnsubscribers.push(
listenToStoreProperty(
(storeState) => getActiveSegmentPosition(storeState),
(activeSegmentPosition) => {
if (activeSegmentPosition != null) {
this.uniforms.activeSegmentPosition.value.set(...activeSegmentPosition);
} else {
this.uniforms.activeSegmentPosition.value.set(-1, -1, -1);
}
},
true,
),
Expand Down
3 changes: 2 additions & 1 deletion frontend/javascripts/oxalis/model/accessors/tool_accessor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,8 @@ export function adaptActiveToolToShortcuts(
activeTool === AnnotationToolEnum.MOVE ||
activeTool === AnnotationToolEnum.ERASE_BRUSH ||
activeTool === AnnotationToolEnum.ERASE_TRACE ||
activeTool === AnnotationToolEnum.QUICK_SELECT
activeTool === AnnotationToolEnum.QUICK_SELECT ||
activeTool === AnnotationToolEnum.PROOFREAD
) {
// These tools do not have any modifier-related behavior currently (except for ALT
// which is already handled below)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,20 @@ export function getVisibleSegments(state: OxalisState): SegmentMap | null | unde
return state.localSegmentationData[layer.name].segments;
}

export function getActiveSegmentPosition(state: OxalisState): Vector3 | null | undefined {
const layer = getVisibleSegmentationLayer(state);
if (layer == null) return null;

const volumeTracing = getVolumeTracingByLayerName(state.tracing, layer.name);
if (volumeTracing == null) return null;

const activeCellId = getActiveCellId(volumeTracing);
if (activeCellId == null) return null;

const segments = getSegmentsForLayer(state, layer.name);
return segments.getNullable(activeCellId)?.somePosition;
}

/*
This function returns the resolution and zoom step in which the given segmentation
tracing layer is currently rendered (if it is rendered). These properties should be used
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,8 @@ export const minCutAgglomerateAction = (sourceNodeId: number, targetNodeId: numb
targetNodeId,
} as const);

export const minCutAgglomerateWithPositionAction = (sourceNodeId: number, position: Vector3) =>
export const minCutAgglomerateWithPositionAction = (position: Vector3) =>
({
type: "MIN_CUT_AGGLOMERATE_WITH_POSITION",
sourceNodeId,
position,
} as const);
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ export type AdHocIsosurfaceInfo = {
mappingName: string | null | undefined;
mappingType: MappingType | null | undefined;
useDataStore?: boolean | null | undefined;
passive?: boolean | null | undefined;
preferredQuality?: number | null | undefined;
};
export type LoadAdHocMeshAction = ReturnType<typeof loadAdHocMeshAction>;
Expand Down
8 changes: 1 addition & 7 deletions frontend/javascripts/oxalis/model/sagas/isosurface_saga.ts
Original file line number Diff line number Diff line change
Expand Up @@ -402,11 +402,7 @@ function* maybeLoadIsosurface(
getSceneController().removeIsosurfaceById(segmentId);
}

getSceneController().addIsosurfaceFromVertices(
vertices,
segmentId,
isosurfaceExtraInfo.passive || false,
);
getSceneController().addIsosurfaceFromVertices(vertices, segmentId);
return neighbors.map((neighbor) => getNeighborPosition(clippedPosition, neighbor));
} catch (exception) {
retryCount++;
Expand Down Expand Up @@ -685,7 +681,6 @@ function* loadPrecomputedMeshForSegmentId(
{ context: sceneController, fn: sceneController.addIsosurfaceFromGeometry },
geometry,
id,
false,
chunk.position,
// Apply the scale from the segment info, which includes dataset scale and mag
scale,
Expand Down Expand Up @@ -715,7 +710,6 @@ function* loadPrecomputedMeshForSegmentId(
{ context: sceneController, fn: sceneController.addIsosurfaceFromGeometry },
geometry,
id,
false,
);
}
},
Expand Down
Loading