分割长短径工具问题修复

uat_us
wangxiaoshuang 2026-03-25 17:46:31 +08:00
parent 64d1ebf350
commit c3a154f762
3 changed files with 306 additions and 38 deletions

View File

@ -538,6 +538,7 @@ import SegmentForm from './SegmentForm.vue'
import colorMap from './colorMap.vue' import colorMap from './colorMap.vue'
import RectangleROITool from './tools/RectangleROITool' import RectangleROITool from './tools/RectangleROITool'
import ScaleOverlayTool from './tools/ScaleOverlayTool' import ScaleOverlayTool from './tools/ScaleOverlayTool'
import SegmentBidirectionalTool from './tools/SegmentBidirectionalTool'
import FixedRadiusCircleROITool from './tools/FixedRadiusCircleROITool' import FixedRadiusCircleROITool from './tools/FixedRadiusCircleROITool'
import uploadDicomAndNonedicom from '@/components/uploadDicomAndNonedicom' import uploadDicomAndNonedicom from '@/components/uploadDicomAndNonedicom'
import downloadDicomAndNonedicom from '@/components/downloadDicomAndNonedicom' import downloadDicomAndNonedicom from '@/components/downloadDicomAndNonedicom'
@ -574,7 +575,7 @@ const {
synchronizers, synchronizers,
LabelMapEditWithContourTool, LabelMapEditWithContourTool,
BrushTool, BrushTool,
SegmentBidirectionalTool, // SegmentBidirectionalTool,
utilities: CStUtils, utilities: CStUtils,
// cursors // cursors
} = cornerstoneTools } = cornerstoneTools

View File

@ -84,7 +84,7 @@
</el-switch> </el-switch>
<span style="margin-left: 5px;">{{ <span style="margin-left: 5px;">{{
$t('trials:reading:Segmentations:title:InactiveSegmentationsShow') $t('trials:reading:Segmentations:title:InactiveSegmentationsShow')
}}</span> }}</span>
</div> </div>
<!-- <div class="SegmentConfig" v-if="SegmentConfig.InactiveSegmentations.show"> <!-- <div class="SegmentConfig" v-if="SegmentConfig.InactiveSegmentations.show">
<span>{{ $t('trials:reading:Segmentations:title:Opacity') }}</span> <span>{{ $t('trials:reading:Segmentations:title:Opacity') }}</span>
@ -133,7 +133,7 @@
<div class="messageBox"> <div class="messageBox">
<el-popover placement="left" :title="item.SegmentLabel" width="200" trigger="hover"> <el-popover placement="left" :title="item.SegmentLabel" width="200" trigger="hover">
<div class="Bidirectionalbox"> <div class="Bidirectionalbox">
<div class="BidirectionalBtn" @click.stop="getBidirectional(item)" <div class="BidirectionalBtn" @click.stop="getBidirectional([item])"
v-if="!item.bidirectional"> v-if="!item.bidirectional">
{{ $t('trials:reading:Segmentations:button:getBidirectional') }} {{ $t('trials:reading:Segmentations:button:getBidirectional') }}
</div> </div>
@ -155,7 +155,7 @@
<div v-for="k in statsKey" :key="k" class="statsBox"> <div v-for="k in statsKey" :key="k" class="statsBox">
<span>{{ k }}</span> <span>{{ k }}</span>
<span v-if="item.stats[k]">{{ Number(item.stats[k].value).toFixed(2) <span v-if="item.stats[k]">{{ Number(item.stats[k].value).toFixed(2)
}}<i>{{ item.stats[k].unit }}</i></span> }}<i>{{ item.stats[k].unit }}</i></span>
</div> </div>
</template> </template>
<div class="serialNum" slot="reference">{{ item.segmentIndex }}</div> <div class="serialNum" slot="reference">{{ item.segmentIndex }}</div>
@ -385,8 +385,11 @@ export default {
this.actionConfiguration.contourBidirectional.data.segmentationId = segmentationId this.actionConfiguration.contourBidirectional.data.segmentationId = segmentationId
this.actionConfiguration.contourBidirectional.data.segmentIndex = segmentIndex this.actionConfiguration.contourBidirectional.data.segmentIndex = segmentIndex
}, },
getBidirectional(item, DATA = null) { getBidirectional(list, DATA = null) {
this.createSegmentConfiguration(item.segmentIndex, item.segmentationId); list.forEach(item => {
this.createSegmentConfiguration(item.segmentIndex, item.segmentationId);
})
const renderingEngine = getRenderingEngine(this.renderingEngineId) const renderingEngine = getRenderingEngine(this.renderingEngineId)
const viewportId = `${this.viewportKey}-${this.activeViewportIndex}` const viewportId = `${this.viewportKey}-${this.activeViewportIndex}`
const viewport = renderingEngine.getViewport(viewportId); const viewport = renderingEngine.getViewport(viewportId);
@ -394,16 +397,20 @@ export default {
[viewport.element].forEach(async (element) => { [viewport.element].forEach(async (element) => {
const bidirectionalData = const bidirectionalData =
await CStUtils.segmentation.getSegmentLargestBidirectional({ await CStUtils.segmentation.getSegmentLargestBidirectional({
segmentationId: item.segmentationId, segmentationId: list[0].segmentationId,
segmentIndices: [item.segmentIndex], segmentIndices: list.map(item => item.segmentIndex),
}); });
if (bidirectionalData.length <= 0) { if (bidirectionalData.length <= 0) {
let annotations = annotation.state.getAllAnnotations().filter(i => i.metadata.segmentationId === item.segmentationId && i.metadata.segmentIndex === item.segmentIndex); list.forEach(item => {
annotations.forEach(i => { let annotations = annotation.state.getAllAnnotations().filter(i => i.metadata.segmentationId === item.segmentationId && i.metadata.segmentIndex === item.segmentIndex);
annotation.state.removeAnnotation(i.annotationUID) annotations.forEach(i => {
annotation.state.removeAnnotation(i.annotationUID)
})
item.bidirectional = null
}) })
this.resetViewport(false) this.resetViewport(false)
item.bidirectional = null
if (DATA) { if (DATA) {
this.segmentationId = DATA.SegmentationId; this.segmentationId = DATA.SegmentationId;
this.segmentIndex = DATA.SegmentMumber; this.segmentIndex = DATA.SegmentMumber;
@ -415,7 +422,7 @@ export default {
bidirectionalData.forEach((bidirectional) => { bidirectionalData.forEach((bidirectional) => {
const { segmentIndex } = bidirectional; const { segmentIndex } = bidirectional;
const { majorAxis, minorAxis, maxMajor, maxMinor } = bidirectional; const { majorAxis, minorAxis, maxMajor, maxMinor } = bidirectional;
let item = list.find(i => i.segmentIndex === segmentIndex)
SegmentBidirectionalTool.hydrate(viewportId, [majorAxis, minorAxis], { SegmentBidirectionalTool.hydrate(viewportId, [majorAxis, minorAxis], {
segmentIndex, segmentIndex,
segmentationId: item.segmentationId, segmentationId: item.segmentationId,
@ -979,9 +986,21 @@ export default {
); );
return; return;
} }
await this.createSegmentation(segmentationId); await this.createSegmentation(segmentationId);
let arr = []
generateToolState.segMetadata.data.forEach(item => {
if (item) {
let Target = JSON.parse(JSON.stringify(item))
arr.push(Target)
}
})
let mapping = {}
arr.forEach((item, index) => {
mapping[index + 1] = Number(item.SegmentNumber)
})
console.log(mapping, 'mapping')
const megmentGroup = const megmentGroup =
segmentation.state.getSegmentation(segmentationId); segmentation.state.getSegmentation(segmentationId);
const { imageIds } = megmentGroup.representationData.Labelmap; const { imageIds } = megmentGroup.representationData.Labelmap;
@ -993,21 +1012,9 @@ export default {
generateToolState.labelmapBufferArray[0] generateToolState.labelmapBufferArray[0]
); );
const remappedData = new Uint8Array(volumeScalarData.length); const remappedData = new Uint8Array(volumeScalarData.length);
let mapping = {}
let segments = await this.getSegmentList(segmentationId)
if (segments.length > 0) {
segments.forEach(item => {
let SegmentJson = item.SegmentJson ? JSON.parse(item.SegmentJson) : {};
if (SegmentJson.bidirectional && SegmentJson.stats) {
let keys = Object.keys(mapping)
mapping[keys.length + 1] = Number(item.SegmentMumber)
}
})
}
for (let i = 0; i < volumeScalarData.length; i++) { for (let i = 0; i < volumeScalarData.length; i++) {
const value = volumeScalarData[i]; const value = volumeScalarData[i];
remappedData[i] = value === 0 ? 0 : (mapping[value] ? mapping[value] : 0); remappedData[i] = value === 0 ? 0 : (mapping[value] ? mapping[value] : value);
} }
for (let i = 0; i < derivedSegmentationImages.length; i++) { for (let i = 0; i < derivedSegmentationImages.length; i++) {
const voxelManager = derivedSegmentationImages[i].voxelManager; const voxelManager = derivedSegmentationImages[i].voxelManager;
@ -1145,14 +1152,14 @@ export default {
this.calculateStatistics([this.segmentIndex], this.segmentationId, 'individual'); this.calculateStatistics([this.segmentIndex], this.segmentationId, 'individual');
let segmentGroup = this.segmentList.find(item => item.segmentationId === this.segmentationId) let segmentGroup = this.segmentList.find(item => item.segmentationId === this.segmentationId)
let segment = segmentGroup.segments.find(item => item.segmentIndex === this.segmentIndex) let segment = segmentGroup.segments.find(item => item.segmentIndex === this.segmentIndex)
this.getBidirectional(segment) this.getBidirectional([segment])
} else { } else {
let segmentGroup = this.segmentList.find(item => item.segmentationId === this.segmentationId) let segmentGroup = this.segmentList.find(item => item.segmentationId === this.segmentationId)
let segmentIndexs = [] let segmentIndexs = []
segmentGroup.segments.forEach(item => { segmentGroup.segments.forEach(item => {
segmentIndexs.push(item.segmentIndex) segmentIndexs.push(item.segmentIndex)
this.getBidirectional(item)
}) })
this.getBidirectional(segmentGroup.segments)
this.calculateStatistics(segmentIndexs, this.segmentationId, 'individual'); this.calculateStatistics(segmentIndexs, this.segmentationId, 'individual');
} }
this.isDel = false this.isDel = false
@ -1339,17 +1346,13 @@ export default {
this.selectSegment(o) this.selectSegment(o)
this.changeColor(s.ColorRgb, o) this.changeColor(s.ColorRgb, o)
this.lockSegment(o, true) this.lockSegment(o, true)
// setTimeout(() => { })
// if (SEGMENT && index === segments.length - 1) { this.$nextTick(() => {
// return this.getBidirectional(o, SEGMENT) if (SEGMENT) {
// }
// this.getBidirectional(o)
// })
if (SEGMENT && index === segments.length - 1) {
// console.log(SEGMENT, 'SEGMENT') // console.log(SEGMENT, 'SEGMENT')
return this.getBidirectional(o, SEGMENT) return this.getBidirectional(obj.segments, SEGMENT)
} }
this.getBidirectional(o) this.getBidirectional(obj.segments)
}) })
} }
} }

View File

@ -0,0 +1,264 @@
// import { getEnabledElement, utilities as csUtils, getEnabledElementByViewportId, utilities, } from '@cornerstonejs/core';
// import { addAnnotation, getAllAnnotations, getAnnotations, removeAnnotation, } from '../../stateManagement/annotation/annotationState';
// import { isAnnotationLocked } from '../../stateManagement/annotation/annotationLocking';
// import { isAnnotationVisible } from '../../stateManagement/annotation/annotationVisibility';
// import { drawLine as drawLineSvg, drawHandles as drawHandlesSvg, } from '../../drawingSvg';
// import { getViewportIdsWithToolToRender } from '../../utilities/viewportFilters';
// import { hideElementCursor } from '../../cursors/elementCursor';
// import triggerAnnotationRenderForViewportIds from '../../utilities/triggerAnnotationRenderForViewportIds';
// import BidirectionalTool from '../annotation/BidirectionalTool';
// import { getSegmentIndexColor } from '../../stateManagement/segmentation/config/segmentationColor';
import { utilities, getEnabledElementByViewportId, getEnabledElement } from '@cornerstonejs/core';
import * as cornerstoneTools from '@cornerstonejs/tools'
const {
annotation,
drawing,
utilities: TSUtilities,
BidirectionalTool,
cursors,
segmentation
} = cornerstoneTools
const { addAnnotation, getAllAnnotations, getAnnotations, removeAnnotation } = annotation.state
const { isAnnotationLocked } = annotation.locking
const { isAnnotationVisible } = annotation.visibility
const { drawLine: drawLineSvg, drawHandles: drawHandlesSvg } = drawing
const { getViewportIdsWithToolToRender } = TSUtilities.viewportFilters
const { triggerAnnotationRenderForViewportIds } = TSUtilities
const { hideElementCursor } = cursors.elementCursor
const { getSegmentIndexColor } = segmentation.config.color
class SegmentBidirectionalTool extends BidirectionalTool {
static { this.toolName = 'SegmentBidirectional'; }
constructor(toolProps = {}) {
super(toolProps);
this.renderAnnotation = (enabledElement, svgDrawingHelper) => {
let renderStatus = true;
const { viewport } = enabledElement;
const { element } = viewport;
const viewportId = viewport.id;
let annotations = getAnnotations(this.getToolName(), element);
if (!annotations?.length) {
return renderStatus;
}
annotations = this.filterInteractableAnnotationsForElement(element, annotations);
if (!annotations?.length) {
return renderStatus;
}
const targetId = this.getTargetId(viewport);
const renderingEngine = viewport.getRenderingEngine();
const styleSpecifier = {
toolGroupId: this.toolGroupId,
toolName: this.getToolName(),
viewportId: enabledElement.viewport.id,
};
for (let i = 0; i < annotations.length; i++) {
const annotation = annotations[i];
const { annotationUID, data } = annotation;
const { points, activeHandleIndex } = data.handles;
const canvasCoordinates = points.map((p) => viewport.worldToCanvas(p));
styleSpecifier.annotationUID = annotationUID;
const { segmentIndex, segmentationId } = annotation.metadata;
const { lineWidth, lineDash, shadow } = this.getAnnotationStyle({
annotation,
styleSpecifier,
});
const colorArray = getSegmentIndexColor(viewportId, segmentationId, segmentIndex) || [255, 255, 255];
// console.log(viewportId, segmentationId, segmentIndex, 'colorArray')
// console.log(colorArray, 'colorArray')
const color = `rgb(${colorArray.slice(0, 3).join(',')})`;
if (!data.cachedStats[targetId] ||
data.cachedStats[targetId].unit == null) {
data.cachedStats[targetId] = {
length: null,
width: null,
unit: null,
};
this._calculateCachedStats(annotation, renderingEngine, enabledElement);
}
else if (annotation.invalidated) {
this._throttledCalculateCachedStats(annotation, renderingEngine, enabledElement);
}
if (!viewport.getRenderingEngine()) {
console.warn('Rendering Engine has been destroyed');
return renderStatus;
}
let activeHandleCanvasCoords;
if (!isAnnotationVisible(annotationUID)) {
continue;
}
if (!isAnnotationLocked(annotationUID) &&
!this.editData &&
activeHandleIndex !== null) {
activeHandleCanvasCoords = [canvasCoordinates[activeHandleIndex]];
}
if (activeHandleCanvasCoords) {
const handleGroupUID = '0';
drawHandlesSvg(svgDrawingHelper, annotationUID, handleGroupUID, activeHandleCanvasCoords, {
color,
});
}
const dataId1 = `${annotationUID}-line-1`;
const dataId2 = `${annotationUID}-line-2`;
const lineUID = '0';
drawLineSvg(svgDrawingHelper, annotationUID, lineUID, canvasCoordinates[0], canvasCoordinates[1], {
color,
lineWidth,
lineDash,
shadow,
}, dataId1);
const secondLineUID = '1';
drawLineSvg(svgDrawingHelper, annotationUID, secondLineUID, canvasCoordinates[2], canvasCoordinates[3], {
color,
lineWidth,
lineDash,
shadow,
}, dataId2);
renderStatus = true;
const textLines = this.configuration.getTextLines(data, targetId);
if (!textLines || textLines.length === 0) {
continue;
}
if (!this.renderLinkedTextBoxAnnotation({
enabledElement,
svgDrawingHelper,
annotation,
styleSpecifier,
textLines,
canvasCoordinates,
})) {
continue;
}
}
return renderStatus;
};
}
addNewAnnotation(evt) {
const eventDetail = evt.detail;
const { currentPoints, element } = eventDetail;
const worldPos = currentPoints.world;
const enabledElement = getEnabledElement(element);
const { viewport } = enabledElement;
this.isDrawing = true;
const camera = viewport.getCamera();
const { viewPlaneNormal, viewUp } = camera;
const referencedImageId = this.getReferencedImageId(viewport, worldPos, viewPlaneNormal, viewUp);
const FrameOfReferenceUID = viewport.getFrameOfReferenceUID();
const annotation = {
highlighted: true,
invalidated: true,
metadata: {
toolName: this.getToolName(),
viewPlaneNormal: [...viewPlaneNormal],
viewUp: [...viewUp],
FrameOfReferenceUID,
referencedImageId,
...viewport.getViewReference({ points: [worldPos] }),
},
data: {
handles: {
points: [
[...worldPos],
[...worldPos],
[...worldPos],
[...worldPos],
],
textBox: {
hasMoved: false,
worldPosition: [0, 0, 0],
worldBoundingBox: {
topLeft: [0, 0, 0],
topRight: [0, 0, 0],
bottomLeft: [0, 0, 0],
bottomRight: [0, 0, 0],
},
},
activeHandleIndex: null,
},
label: '',
cachedStats: {},
},
};
addAnnotation(annotation, element);
const viewportIdsToRender = getViewportIdsWithToolToRender(element, this.getToolName());
this.editData = {
annotation,
viewportIdsToRender,
handleIndex: 1,
movingTextBox: false,
newAnnotation: true,
hasMoved: false,
};
this._activateDraw(element);
hideElementCursor(element);
evt.preventDefault();
triggerAnnotationRenderForViewportIds(viewportIdsToRender);
return annotation;
}
static {
this.hydrate = (viewportId, axis, options) => {
const enabledElement = getEnabledElementByViewportId(viewportId);
if (!enabledElement) {
return;
}
const { viewport } = enabledElement;
const existingAnnotations = getAllAnnotations();
const toolAnnotations = existingAnnotations.filter((annotation) => annotation.metadata.toolName === 'SegmentBidirectional');
const existingAnnotation = toolAnnotations.find((annotation) => {
const { metadata } = annotation;
if (metadata.segmentIndex === options?.segmentIndex &&
metadata.segmentationId === options?.segmentationId) {
return true;
}
return false;
});
if (existingAnnotation) {
removeAnnotation(existingAnnotation.annotationUID);
}
const { FrameOfReferenceUID, referencedImageId, viewPlaneNormal, instance, } = this.hydrateBase(SegmentBidirectionalTool, enabledElement, axis[0], options);
const [majorAxis, minorAxis] = axis;
const [major0, major1] = majorAxis;
const [minor0, minor1] = minorAxis;
const points = [major0, major1, minor0, minor1];
const { toolInstance, ...serializableOptions } = options || {};
const annotation = {
annotationUID: options?.annotationUID || utilities.uuidv4(),
data: {
handles: {
points,
activeHandleIndex: null,
textBox: {
hasMoved: false,
worldPosition: [0, 0, 0],
worldBoundingBox: {
topLeft: [0, 0, 0],
topRight: [0, 0, 0],
bottomLeft: [0, 0, 0],
bottomRight: [0, 0, 0],
},
},
},
cachedStats: {},
},
highlighted: false,
autoGenerated: false,
invalidated: false,
isLocked: false,
isVisible: true,
metadata: {
segmentIndex: options?.segmentIndex,
segmentationId: options?.segmentationId,
toolName: instance.getToolName(),
viewPlaneNormal,
FrameOfReferenceUID,
referencedImageId,
...serializableOptions,
},
};
addAnnotation(annotation, viewport.element);
triggerAnnotationRenderForViewportIds([viewport.id]);
return annotation;
};
}
}
export default SegmentBidirectionalTool;