feat: orthanc启动日志
This commit is contained in:
parent
1c488ef76e
commit
6aa316efbf
18
README.md
18
README.md
|
@ -38,4 +38,20 @@ pnpm config set virtual-store-dir-max-length 70
|
||||||
- 心脏结构窗
|
- 心脏结构窗
|
||||||
窗宽:500 HU
|
窗宽:500 HU
|
||||||
窗位:50 HU
|
窗位:50 HU
|
||||||
适用于查看整体心脏结构,包括心室腔、心包和大血管。
|
适用于查看整体心脏结构,包括心室腔、心包和大血管。
|
||||||
|
|
||||||
|
|
||||||
|
## 备忘
|
||||||
|
|
||||||
|
- AXIAL(轴位):
|
||||||
|
• 方向:横断面,与身体的长轴垂直。
|
||||||
|
• 描述:将身体分为上(头部)和下(脚部)部分。
|
||||||
|
• 应用:通常用于查看从头顶到脚底的切片图像。
|
||||||
|
- SAGITTAL(矢状位):
|
||||||
|
• 方向:纵向面,沿身体的前后方向。
|
||||||
|
• 描述:将身体分为左、右两部分。正中矢状面则正好将身体分为左右对称的两半。
|
||||||
|
• 应用:用于观察身体的侧面结构,如脊柱的排列。
|
||||||
|
- CORONAL(冠状位):
|
||||||
|
• 方向:冠状面,与矢状面垂直,沿身体的左右方向。
|
||||||
|
• 描述:将身体分为前(腹侧)和后(背侧)部分。
|
||||||
|
• 应用:适用于查看从前面到后面的结构,如面部和脑部的解剖。
|
|
@ -27,8 +27,8 @@ export const runOrthancServer = (pacsPath: string) => {
|
||||||
if (existsSync(pacsPath)) {
|
if (existsSync(pacsPath)) {
|
||||||
const configPath = path.join(path.dirname(pacsPath), "config.json");
|
const configPath = path.join(path.dirname(pacsPath), "config.json");
|
||||||
const child_process = spawn(pacsPath, [configPath]);
|
const child_process = spawn(pacsPath, [configPath]);
|
||||||
child_process.stdout.on("data", (data) => log.info(data));
|
child_process.stdout.on("data", (data) => log.info(data.toString()));
|
||||||
child_process.stderr.on("data", (data) => log.error(data));
|
child_process.stderr.on("data", (data) => log.error(data.toString()));
|
||||||
} else {
|
} else {
|
||||||
console.error("pacsPath is a not exist");
|
console.error("pacsPath is a not exist");
|
||||||
log.error("pacsPath is a not exist");
|
log.error("pacsPath is a not exist");
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
export const renderingEngineId = "mprRenderingEngine";
|
export const renderingEngineId = "mprRenderingEngine";
|
||||||
|
|
||||||
export const viewportId1 = "CT_AXIAL";
|
export type ViewportId = "CT_AXIAL" | "CT_SAGITTAL" | "CT_CORONAL";
|
||||||
export const viewportId2 = "CT_SAGITTAL";
|
|
||||||
export const viewportId3 = "CT_CORONAL";
|
export const viewportId1: ViewportId = "CT_AXIAL";
|
||||||
export const toolGroupId = "group";
|
export const viewportId2: ViewportId = "CT_SAGITTAL";
|
||||||
|
export const viewportId3: ViewportId = "CT_CORONAL";
|
||||||
|
|
||||||
export const viewportColors = {
|
export const viewportColors = {
|
||||||
[viewportId1]: "rgb(200, 0, 0)",
|
[viewportId1]: "rgb(200, 0, 0)",
|
||||||
|
@ -11,7 +12,7 @@ export const viewportColors = {
|
||||||
[viewportId3]: "rgb(0, 200, 0)",
|
[viewportId3]: "rgb(0, 200, 0)",
|
||||||
};
|
};
|
||||||
|
|
||||||
export const viewportReferenceLineControllable = [
|
export const viewportReferenceLineControllable: ViewportId[] = [
|
||||||
viewportId1,
|
viewportId1,
|
||||||
viewportId2,
|
viewportId2,
|
||||||
viewportId3,
|
viewportId3,
|
||||||
|
|
|
@ -17,10 +17,16 @@ import {
|
||||||
viewportId1,
|
viewportId1,
|
||||||
viewportId2,
|
viewportId2,
|
||||||
viewportId3,
|
viewportId3,
|
||||||
|
ViewportId,
|
||||||
} from "./Crosshair.config";
|
} from "./Crosshair.config";
|
||||||
|
|
||||||
const { ToolGroupManager, CrosshairsTool, StackScrollMouseWheelTool, WindowLevelTool, Enums: csToolsEnums } =
|
const {
|
||||||
cornerstoneTools;
|
ToolGroupManager,
|
||||||
|
CrosshairsTool,
|
||||||
|
StackScrollMouseWheelTool,
|
||||||
|
WindowLevelTool,
|
||||||
|
Enums: csToolsEnums,
|
||||||
|
} = cornerstoneTools;
|
||||||
|
|
||||||
const { MouseBindings } = csToolsEnums;
|
const { MouseBindings } = csToolsEnums;
|
||||||
|
|
||||||
|
@ -30,23 +36,22 @@ interface CrosshairMprProps {
|
||||||
children?: JSX.Element;
|
children?: JSX.Element;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getReferenceLineColor(viewportId: string | number) {
|
function getReferenceLineColor(vpId: ViewportId) {
|
||||||
return viewportColors[viewportId];
|
return viewportColors[vpId];
|
||||||
}
|
}
|
||||||
|
|
||||||
function getReferenceLineControllable(viewportId: string) {
|
function getReferenceLineControllable(vpId: ViewportId) {
|
||||||
const index = viewportReferenceLineControllable.indexOf(viewportId);
|
const index = viewportReferenceLineControllable.indexOf(vpId);
|
||||||
return index !== -1;
|
return index !== -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getReferenceLineDraggableRotatable(viewportId: string) {
|
function getReferenceLineDraggableRotatable(vpId: ViewportId) {
|
||||||
const index = viewportReferenceLineDraggableRotatable.indexOf(viewportId);
|
const index = viewportReferenceLineDraggableRotatable.indexOf(vpId);
|
||||||
return index !== -1;
|
return index !== -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getReferenceLineSlabThicknessControlsOn(viewportId: string) {
|
function getReferenceLineSlabThicknessControlsOn(vpId: ViewportId) {
|
||||||
const index =
|
const index = viewportReferenceLineSlabThicknessControlsOn.indexOf(vpId);
|
||||||
viewportReferenceLineSlabThicknessControlsOn.indexOf(viewportId);
|
|
||||||
return index !== -1;
|
return index !== -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,19 +61,25 @@ interface CrosshairMprProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const CrosshairMpr = (props: CrosshairMprProps) => {
|
export const CrosshairMpr = (props: CrosshairMprProps) => {
|
||||||
const viewportId1Ref = useRef(null);
|
const viewportRef_AXIAL = useRef<HTMLDivElement | null>(null);
|
||||||
const viewportId2Ref = useRef(null);
|
const viewportRef_SAGITTAL = useRef<HTMLDivElement | null>(null);
|
||||||
const viewportId3Ref = useRef(null);
|
const viewportRef_CORONAL = useRef<HTMLDivElement | null>(null);
|
||||||
const renderingEngine = useRef<RenderingEngine>();
|
const renderingEngine = useRef<RenderingEngine>();
|
||||||
const imageIds = useRef<string[]>();
|
const imageIds = useRef<string[]>();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
||||||
cornerstoneTools.addTool(StackScrollMouseWheelTool);
|
cornerstoneTools.addTool(StackScrollMouseWheelTool);
|
||||||
cornerstoneTools.addTool(CrosshairsTool);
|
cornerstoneTools.addTool(CrosshairsTool);
|
||||||
cornerstoneTools.addTool(WindowLevelTool);
|
cornerstoneTools.addTool(WindowLevelTool);
|
||||||
|
|
||||||
const run = async () => {
|
const run = async () => {
|
||||||
|
if (
|
||||||
|
!viewportRef_AXIAL.current ||
|
||||||
|
!viewportRef_SAGITTAL.current ||
|
||||||
|
!viewportRef_CORONAL.current
|
||||||
|
)
|
||||||
|
return;
|
||||||
|
|
||||||
imageIds.current = await createImageIdsAndCacheMetaData({
|
imageIds.current = await createImageIdsAndCacheMetaData({
|
||||||
StudyInstanceUID: props.StudyInstanceUID,
|
StudyInstanceUID: props.StudyInstanceUID,
|
||||||
SeriesInstanceUID: props.SeriesInstanceUID,
|
SeriesInstanceUID: props.SeriesInstanceUID,
|
||||||
|
@ -86,17 +97,17 @@ export const CrosshairMpr = (props: CrosshairMprProps) => {
|
||||||
);
|
);
|
||||||
|
|
||||||
// 默认windowWidtth
|
// 默认windowWidtth
|
||||||
const { windowCenter, windowWidth } = volume.cornerstoneImageMetaData
|
const { windowCenter, windowWidth } = volume.cornerstoneImageMetaData;
|
||||||
const defaultWindowCenter = 50
|
const defaultWindowCenter = 50;
|
||||||
const defaultWindowWidth = 850
|
const defaultWindowWidth = 850;
|
||||||
console.log(2, windowCenter, windowWidth)
|
console.log(2, windowCenter, windowWidth);
|
||||||
|
|
||||||
// Create the viewports
|
// Create the viewports
|
||||||
const viewportInputArray: PublicViewportInput[] = [
|
const viewportInputArray: PublicViewportInput[] = [
|
||||||
{
|
{
|
||||||
viewportId: viewportId1,
|
viewportId: viewportId1,
|
||||||
type: ViewportType.ORTHOGRAPHIC,
|
type: ViewportType.ORTHOGRAPHIC,
|
||||||
element: viewportId1Ref.current!,
|
element: viewportRef_AXIAL.current,
|
||||||
defaultOptions: {
|
defaultOptions: {
|
||||||
orientation: CoreEnums.OrientationAxis.AXIAL,
|
orientation: CoreEnums.OrientationAxis.AXIAL,
|
||||||
background: [0, 0, 0],
|
background: [0, 0, 0],
|
||||||
|
@ -105,7 +116,7 @@ export const CrosshairMpr = (props: CrosshairMprProps) => {
|
||||||
{
|
{
|
||||||
viewportId: viewportId2,
|
viewportId: viewportId2,
|
||||||
type: ViewportType.ORTHOGRAPHIC,
|
type: ViewportType.ORTHOGRAPHIC,
|
||||||
element: viewportId2Ref.current!,
|
element: viewportRef_SAGITTAL.current,
|
||||||
defaultOptions: {
|
defaultOptions: {
|
||||||
orientation: CoreEnums.OrientationAxis.SAGITTAL,
|
orientation: CoreEnums.OrientationAxis.SAGITTAL,
|
||||||
background: [0, 0, 0],
|
background: [0, 0, 0],
|
||||||
|
@ -114,7 +125,7 @@ export const CrosshairMpr = (props: CrosshairMprProps) => {
|
||||||
{
|
{
|
||||||
viewportId: viewportId3,
|
viewportId: viewportId3,
|
||||||
type: ViewportType.ORTHOGRAPHIC,
|
type: ViewportType.ORTHOGRAPHIC,
|
||||||
element: viewportId3Ref.current!,
|
element: viewportRef_CORONAL.current,
|
||||||
defaultOptions: {
|
defaultOptions: {
|
||||||
orientation: CoreEnums.OrientationAxis.CORONAL,
|
orientation: CoreEnums.OrientationAxis.CORONAL,
|
||||||
background: [0, 0, 0],
|
background: [0, 0, 0],
|
||||||
|
@ -133,7 +144,12 @@ export const CrosshairMpr = (props: CrosshairMprProps) => {
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
volumeId: props.SeriesInstanceUID,
|
volumeId: props.SeriesInstanceUID,
|
||||||
callback: ({ volumeActor }) => setCtTransferFunctionForVolumeActor({ volumeActor, defaultWindowCenter, defaultWindowWidth }),
|
callback: ({ volumeActor }) =>
|
||||||
|
setCtTransferFunctionForVolumeActor({
|
||||||
|
volumeActor,
|
||||||
|
defaultWindowCenter,
|
||||||
|
defaultWindowWidth,
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
[viewportId1, viewportId2, viewportId3]
|
[viewportId1, viewportId2, viewportId3]
|
||||||
|
@ -187,17 +203,18 @@ export const CrosshairMpr = (props: CrosshairMprProps) => {
|
||||||
]);
|
]);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!props.SeriesInstanceUID && !props.StudyInstanceUID) return;
|
if (props.SeriesInstanceUID && props.StudyInstanceUID) {
|
||||||
run();
|
run();
|
||||||
|
}
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
cornerstoneTools.removeTool(StackScrollMouseWheelTool);
|
cornerstoneTools.removeTool(StackScrollMouseWheelTool);
|
||||||
cornerstoneTools.removeTool(CrosshairsTool);
|
cornerstoneTools.removeTool(CrosshairsTool);
|
||||||
cornerstoneTools.removeTool(WindowLevelTool)
|
cornerstoneTools.removeTool(WindowLevelTool);
|
||||||
|
renderingEngine.current?.destroy();
|
||||||
ToolGroupManager.destroyToolGroup(props.SeriesInstanceUID);
|
ToolGroupManager.destroyToolGroup(props.SeriesInstanceUID);
|
||||||
};
|
};
|
||||||
}, [props.StudyInstanceUID, props.SeriesInstanceUID]);
|
}, [props]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const resize = () => renderingEngine.current?.resize();
|
const resize = () => renderingEngine.current?.resize();
|
||||||
|
@ -207,11 +224,19 @@ export const CrosshairMpr = (props: CrosshairMprProps) => {
|
||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const onDBClickViewport = (viewportRef) => {
|
||||||
|
console.log("dblcik", viewportRef);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="h-full flex flex-col gap-y-2">
|
<div className="h-full flex flex-col gap-y-2">
|
||||||
<div className="h-1/3 border rounded-md" ref={viewportId1Ref}></div>
|
<div
|
||||||
<div className="h-1/3 border rounded-md" ref={viewportId2Ref}></div>
|
onDoubleClick={() => onDBClickViewport(viewportRef_AXIAL)}
|
||||||
<div className="h-1/3 border rounded-md" ref={viewportId3Ref}></div>
|
className="h-1/3 border rounded-md"
|
||||||
|
ref={viewportRef_AXIAL}
|
||||||
|
></div>
|
||||||
|
<div className="h-1/3 border rounded-md" ref={viewportRef_SAGITTAL}></div>
|
||||||
|
<div className="h-1/3 border rounded-md" ref={viewportRef_CORONAL}></div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -3,15 +3,27 @@ import { initCornerstone } from "./MprViewer/CornerstoneDicomLoader/init";
|
||||||
import { CrosshairMpr } from "./MprViewer/Crosshair";
|
import { CrosshairMpr } from "./MprViewer/Crosshair";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
|
|
||||||
|
export interface CurrentDicom {
|
||||||
|
SeriesInstanceUID: string | null;
|
||||||
|
StudyInstanceUID: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
export const Viewer = () => {
|
export const Viewer = () => {
|
||||||
const [cornerstoneLoaded, setCornerstoneLoaded] = useState(false);
|
const [cornerstoneLoaded, setCornerstoneLoaded] = useState(false);
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const queryParams = new URLSearchParams(location.search);
|
const queryParams = new URLSearchParams(location.search);
|
||||||
const SeriesInstanceUID = queryParams.get("SeriesInstanceUID"); // 获取URL参数
|
const [currentDicom, setCurrentDicom] = useState<CurrentDicom>({
|
||||||
const StudyInstanceUID = queryParams.get("StudyInstanceUID"); // 获取URL参数
|
SeriesInstanceUID: queryParams.get("SeriesInstanceUID"),
|
||||||
|
StudyInstanceUID: queryParams.get("StudyInstanceUID"),
|
||||||
|
});
|
||||||
|
|
||||||
console.log(StudyInstanceUID);
|
useEffect(() => {
|
||||||
console.log(SeriesInstanceUID);
|
const { SeriesInstanceUID, StudyInstanceUID } = currentDicom;
|
||||||
|
if (StudyInstanceUID && SeriesInstanceUID) {
|
||||||
|
const metadata = { SeriesInstanceUID, StudyInstanceUID };
|
||||||
|
localStorage.setItem("viewCache", JSON.stringify(metadata));
|
||||||
|
}
|
||||||
|
}, [currentDicom]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
initCornerstone().then(() => setCornerstoneLoaded(true));
|
initCornerstone().then(() => setCornerstoneLoaded(true));
|
||||||
|
@ -21,12 +33,15 @@ export const Viewer = () => {
|
||||||
<div className="w-full h-full flex">
|
<div className="w-full h-full flex">
|
||||||
<div className="w-2/3 h-full">vr</div>
|
<div className="w-2/3 h-full">vr</div>
|
||||||
<div className="w-1/3 h-full">
|
<div className="w-1/3 h-full">
|
||||||
{cornerstoneLoaded && StudyInstanceUID && SeriesInstanceUID && (
|
{cornerstoneLoaded &&
|
||||||
<CrosshairMpr
|
currentDicom.StudyInstanceUID &&
|
||||||
StudyInstanceUID={StudyInstanceUID}
|
currentDicom.SeriesInstanceUID && (
|
||||||
SeriesInstanceUID={SeriesInstanceUID}
|
<CrosshairMpr
|
||||||
/>
|
StudyInstanceUID={currentDicom.StudyInstanceUID}
|
||||||
)}
|
SeriesInstanceUID={currentDicom.SeriesInstanceUID}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{Object.values(currentDicom).some((i) => !i) && "导入dicom"}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user