header wave

Post

프로젝트) 의료이미지 라벨링 사이트 - 2

2022-09-20 AM 07/21
#react
#javascript
#study
#project

뷰를 완성한 뒤, 본격적으로 Dicom 이미지를 불러오는 기능을 구현했다.

Dicom 파일은 jpeg, jpg 같은 일반 이미지 파일과 다르다.

대학교 의료영상학 시간에 배웠던 기억에 따르면, 일반 이미지는 픽셀이라는 단위로 되어있지만, Dicom 이미지는 Voxel 이라는 3차원 단위로 되어있어서 다시 2D Pixel로 바꿔주는 과정이 필요하다.

JS 라이브러이 중에 dicomParser.js 란 라이브러리가 있는데 3D Voxel 데이터에서 2D 픽셀데이터로 쉽게 바꿔주었다.

바뀐 2D 데이터를 HTML 페이지에 로딩하는 과정도 필요했는데, cornerstone.js란 라이브러리가 이 과정을 쉽게 해줬다.

https://docs.cornerstonejs.org/ Introduction · cornerstone No results matching "" docs.cornerstonejs.org

공식 Docs에서 확인해보면 웹에서 Dicom 파일을 로드하여 2D 픽셀데이터를 추출한 뒤, HTML canvas에 그려주는 기능까지 수행해주는 라이브러리인 것을 확인할 수 있다.

게다가 HTML Canvas를 사용하기 때문에, 다양한 tool(길이측정, 마킹, 텍스트 작성 등)들을 제공하고 있어 응용성이 매우 높았다.

1) 이미지 로드하기

img.png

현재 콤포넌트 구조는 현재 이렇다. AddImage 컴포넌트에서 로컬에 있는 Dicom 파일을 추가하게 되는데, 이 추가된 다이콤 파일을 ImageBox에서도 읽어들여 HTML Canvas에 로딩해야 했다.

그래서 MainPage 컴포넌트에 files state를 만들어 하향식으로 데이터 흐름을 구성했다.

files, setFiles를 통해 Dicom 파일을 state에 저장한다.

MainPage 컴포넌트

const Mainpage = () => {
  const [files, setFiles] = useState([]);

  const classes = useStyles();
  return (
    <div className={classes.container}>
      <SideBar files={files} setFiles={setFiles} />
      <ImageBox files={files} />
    </div>
  );
};

export default Mainpage;

AddImage 컴포넌트에서, 로컬 파일들을 선택하면 상위 state의 files에 저장해준다.

중요한 것은 다이콤 파일들을 그대로 저장하는 것이 아니라, cornerstone image loader 기능을 사용하여,

HTML canvas에 그릴 수 있는 픽셀데이터 형식으로 변한한뒤, state에 저장했다.

AddImage 컴포넌트

  const selectFile = (e) => {
    const before_converted = [...e.target.files];
    const converted = before_converted.map((file) => {
      return cornerstoneWADOImageLoader.wadouri.fileManager.add(file); // date format converting
    });

    setFiles([...files, ...converted]);
  };

마지막으로 imageBox 하위의 imageShow 컴포넌트에서, 상위 state의 files(2d pixel)를 불러와 Dom에 나타냈다.

import { useEffect, useState } from "react";
import useStyles from "../css/useStyles.js";

import cornerstone from "cornerstone-core";
import cornerstoneTools from "cornerstone-tools";

const ImageShow = ({ files }) => {
  let element;
  const classes = useStyles();

  useEffect(() => {
    if (files.length !== 0) {
      element = document.getElementById("dicomImage"); // html canvas를 추가할 dom 요소를 선택해준다.
      cornerstone.enable(element); // cornerstone 라이브러리에서도 dome 요소를 사용할 수 있도록 추가해주는 과정이다. (안하면 null값이 나옴)

      // dicom 이미지를 html 그려주는 역할을 수행하는 function
      const loadFile = (imgIds) => {
        // 마우스 휠로 이미지를 변경할 수 있는 기능을 위한 변수다.
        const StackScrollMouseWheelTool =
          cornerstoneTools.StackScrollMouseWheelTool;

        // 여러 dicom 파일을 한 묶음으로 관리할 수 있게 해주는 기능이다.
        const stack = {
          currentImageIdIndex: 0,
          imageIds: imgIds,
        };

        // console.log("이미지 아이디", imageIds);

        // 이미지를 불러오는 과정이다.
        cornerstone.loadImage(imgIds[0]).then((image) => {
          cornerstone.displayImage(element, image); // 이미지를 html canvas에 그려준다.
          cornerstoneTools.addStackStateManager(element, ["stack"]); // dom 요소에 stack을 추가한다.
          cornerstoneTools.addToolState(element, "stack", stack); // stack에 tool 요소도 추가할 수 있게 해준다.
        });

        cornerstoneTools.addTool(StackScrollMouseWheelTool);
        cornerstoneTools.setToolActive("StackScrollMouseWheel", {});
      };

      loadFile(files);
    }
  }, [files]);

앞으로 추가작업

  • 라벨링할 수 있도록 Drawing Tool 제작

HTML canvas의 이미지에 라벨링을 할 수 있는 기능을 툴을 제작해야 한다.

  • Redux를 사용한 상태관리

state로 상태관리를 하려니, 공통적으로 쓰는 state를 상위에서 top-down으로 계속 내리니 중복 코드가 많이 작성되고, 렌더링 측면에서 비효율적이었다. Redux를 사용한 전역 상태관리를 적용할 계획이다.