prerakmody
prerakmody

Reputation: 116

(Cornerstone.js) Contour editing not intuitive with FreehandRoiSculptorTool

Goal I am trying to use FreehandRoiSculptorTool for contour editing on a contour created by the FreehandRoiTool.

Issue If you look at the attached .gif, I purposely make an extension on the contour that I wish to remove. But using the FreehandRoiSculptorTool , I face the following issues

  1. I am unable to see the tool itself. Is it because I've zoomed in?
  2. I also unable to achieve the desired effect (i.e, removing the extension with the FreehandRoiSculptorTool). Maybe there is another tool for this. But I was hoping I could stick to one tool to do all forms of contour editing.
  3. Also, is there a way to control the radius of this tool?

Contour editing using FreehandRoiSculptorTool

<!DOCTYPE html>
<html>
  <head>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/hammer.js/2.0.8/hammer.min.js"></script>
    
    <script src="https://unpkg.com/cornerstone-core/dist/cornerstone.js"></script> <!-- cornerstone-core - 2.6.1 - 2021-11-19 -->
    <script src="https://unpkg.com/cornerstone-tools/dist/cornerstoneTools.js"></script> <!-- cornerstone-tools - 6.0.10 - 2023-07-21 -->
    <script src="https://unpkg.com/cornerstone-math/dist/cornerstoneMath.js"></script> <!-- cornerstone-math - 0.1.10 - 2022-06-09 -->

    <script src="https://unpkg.com/dicom-parser/dist/dicomParser.js"></script>
    <script src="https://unpkg.com/cornerstone-wado-image-loader/dist//cornerstoneWADOImageLoader.bundle.min.js"></script>

    <!-- create a css block-->
    <style>
      .pressed {
        background-color: #259736;
      }
    </style>
    
  </head>
  <body>
    
    <input type="file" id="dicomFolder" webkitdirectory multiple />
    <p>
      Click on Mouse Scroll to pan. <br> 
      Zoom using Right Mouse Button. <br> 
      Draw/Sculpt Contours using Left Mouse Button. <br>
      Press 'Esc' to get out of an incomplete contour. <br>
      Press 'r' to reset the stack (not working!). <br>
    </p>
    <div id="content" style="display: flex; align-items: stretch; justify-content: stretch;">
      
      <!-- <button id="freehandRoiButton" style="display: none;">Draw</button> -->
    </div>

    <script>
      
      // Step 0.1 - Enable debugging to see verbose logs
      localStorage.setItem("debug", "cornerstoneTools")

      // Step 0.2 - Connect libraries
      cornerstoneTools.external.Hammer = Hammer;
      cornerstoneTools.external.cornerstoneMath = cornerstoneMath;
      cornerstoneWADOImageLoader.external.cornerstone = cornerstone;
      cornerstoneWADOImageLoader.external.cornerstoneTools = cornerstoneTools;
      
      // Step 0.3 - Initialize libraries
      cornerstoneTools.init()
      
      // Step 0.4 - Enable main div
      var element = document.getElementById('content');
      cornerstone.enable(element);

      // Step 0.5 - gobal vars
      var isFreehandRoiActive = false;
      var isContourSculptorActive = false;

      // Step 1 - Get .dcm folder
      document.getElementById('dicomFolder').addEventListener('change', async function(e) {
        
        // Step 1.1 - get WADO image Ids
        var files = e.target.files;
        var imageIds = Array.from(files).map(file => {
          return cornerstoneWADOImageLoader.wadouri.fileManager.add(file);
        });
        
        // Step 1.2 - Load and sort images based on InstanceNumber
        var images = await Promise.all(imageIds.map(id => cornerstone.loadImage(id)));
        var firstImage = images[0];
        element.style.width = firstImage.columns + 'px';
        element.style.height = firstImage.rows + 'px';
        images.sort((a, b) => parseInt(dicomParser.parseDicom(a.data.byteArray).string('x00200013')) - dicomParser.parseDicom(b.data.byteArray).string('x00200013'));
        imageIds = images.map(image => image.imageId);
        
        // Step 1.3 - Load all images in the stack
        var middleImageIdx = parseInt(imageIds.length/2);
        var stack = {
          currentImageIdIndex: middleImageIdx,
          imageIds: imageIds
        };

        // Step 1.4 - Load images and set the stack
        cornerstone.loadAndCacheImage(imageIds[middleImageIdx]).then((image) => {
        // cornerstone.loadImage(imageIds[parseInt(imageIds.length/2)]).then((image) => {

          // Step 1.4.1 - Show first image
          cornerstone.displayImage(element, image)
          
          // Step 1.4.2 - Set width and height
          var canvas = document.querySelector('#content canvas');
          canvas.width = image.columns
          canvas.height = image.rows
          canvas.addEventListener('contextmenu', function(event) {
            event.preventDefault();
          });
          
          // Step 1.4.3 - Add stack state manager and tool state
          cornerstoneTools.addStackStateManager(element, ['stack'])
          cornerstoneTools.addToolState(element, 'stack', stack)

          // Step 1.4.4 - Make buttons
          var freehandRoiButton = document.createElement("button")
          freehandRoiButton.id = "freehandRoiButton"
          freehandRoiButton.innerHTML = "Draw"
          element.appendChild(freehandRoiButton)

          var contourSculptorButton = document.createElement("button");
          contourSculptorButton.id = "contourSculptorButton";
          contourSculptorButton.innerHTML = "Contour Sculpting";
          element.appendChild(contourSculptorButton);

          // Step 1.4.4.1 - Events for FreehandRoi
          freehandRoiButton.addEventListener('click', function() {
            isFreehandRoiActive = !isFreehandRoiActive;
            
            
            if (isFreehandRoiActive) {
              cornerstoneTools.setToolActive('FreehandRoi', { mouseButtonMask: 1 });
              freehandRoiButton.classList.add('pressed');
              cornerstoneTools.setToolPassive('FreehandRoiSculptor', {});
              contourSculptorButton.classList.remove('pressed');
              isContourSculptorActive = false;
            } else {
              cornerstoneTools.setToolPassive('FreehandRoi', {});
              freehandRoiButton.classList.remove('pressed');
            }
          });

          // Step 1.4.4.2 - Events for  contourSculptorButton
          contourSculptorButton.addEventListener('click', function() {
            isContourSculptorActive = !isContourSculptorActive;

            if (isContourSculptorActive) {
              cornerstoneTools.setToolActive('FreehandRoiSculptor', { mouseButtonMask: 1 });
              contourSculptorButton.classList.add('pressed');
              cornerstoneTools.setToolPassive('FreehandRoi', {});
              freehandRoiButton.classList.remove('pressed');
              isFreehandRoiActive = false;
            } else {
              cornerstoneTools.setToolPassive('FreehandRoiSculptor', {});
              contourSculptorButton.classList.remove('pressed');
            }
          });

        })

      });

      // Step 2 - Add tools
      // Step 2.1 - Add mouse wheel tool
      const StackScrollMouseWheelTool = cornerstoneTools.StackScrollMouseWheelTool
      cornerstoneTools.addTool(StackScrollMouseWheelTool)
      cornerstoneTools.setToolActive('StackScrollMouseWheel', { })

      // Step 2.1 - Add freehand tool (left mouse button)
      // https://tools.cornerstonejs.org/examples/tools/freehand-mouse.html
      const FreehandRoiTool = cornerstoneTools.FreehandRoiTool
      cornerstoneTools.addTool(FreehandRoiTool)

      // Step 2.2 - Add the contour sculptor tool
      const FreehandRoiSculptorTool = cornerstoneTools.FreehandRoiSculptorTool;
      cornerstoneTools.addTool(FreehandRoiSculptorTool);
      cornerstoneTools.setToolActive('FreehandRoiSculptor', {});
      // var config = cornerstoneTools.getToolState('FreehandRoiSculptor');
      // console.log(config);
      
      // Step 2.3 - Add zoom tool (right mouse button)
      const ZoomTool = cornerstoneTools.ZoomTool
      cornerstoneTools.addTool(ZoomTool)
      cornerstoneTools.setToolActive('Zoom', { mouseButtonMask: 2 })

      // Step 2.4 - Add pan tool (middle mouse button)
      const PanTool = cornerstoneTools.PanTool;
      cornerstoneTools.addTool(PanTool);
      cornerstoneTools.setToolActive('Pan', { mouseButtonMask: 4 });

      // Step 3 - Event listeners
      document.addEventListener('keydown', function(event) {
        const freehandRoiToolState = cornerstoneTools.getToolState(element, 'FreehandRoi');

        if (event.key === 'Escape') {
          console.log('Escape pressed');
          if (freehandRoiToolState && freehandRoiToolState.data && freehandRoiToolState.data.length > 0) {
            if (freehandRoiToolState.data[freehandRoiToolState.data.length - 1].active == true){
              cornerstoneTools.setToolPassive('FreehandRoi', {});
              freehandRoiToolState.data.pop();
              cornerstone.updateImage(element);
              cornerstoneTools.setToolActive('FreehandRoi', { mouseButtonMask: 1 })
            }            
          }
        }

        if (event.key === 'r') {
          console.log('r pressed');
          const stackData = cornerstoneTools.getToolState(element, 'stack');
          if (stackData && stackData.data && stackData.data.length > 0 && stackData.data[0].imageIds.length > 0) {
            
            const middleSliceIndex = Math.floor(stackData.data[0].imageIds.length / 2);

            // Trial 1
            stackData.data[0].currentImageIdIndex = middleSliceIndex;
            cornerstoneTools.addToolState(element, 'stack', stackData)
            cornerstone.updateImage(element);

          }
        }

      });

    </script>

  </body>
</html>

Versions

So my final goal is to create something like the video below. Its taken from a commercial tool. enter image description here

Upvotes: 1

Views: 227

Answers (0)

Related Questions