Press n or j to go to the next uncovered block, b, p or k for the previous block.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 | import { inv, multiply } from 'mathjs'; // TODO -> This is pulled out of some internal logic from Dicom Microscopy Viewer, // We should likely just expose this there. export default function coordinateFormatScoord3d2Geometry(coordinates, pyramid) { let transform = false; if (!Array.isArray(coordinates[0])) { coordinates = [coordinates]; transform = true; } const metadata = pyramid[pyramid.length - 1]; const orientation = metadata.ImageOrientationSlide; const spacing = _getPixelSpacing(metadata); const origin = metadata.TotalPixelMatrixOriginSequence[0]; const offset = [ Number(origin.XOffsetInSlideCoordinateSystem), Number(origin.YOffsetInSlideCoordinateSystem), ]; coordinates = coordinates.map(c => { const slideCoord = [c[0], c[1]]; const pixelCoord = mapSlideCoord2PixelCoord({ offset, orientation, spacing, point: slideCoord, }); return [pixelCoord[0], -(pixelCoord[1] + 1), 0]; }); if (transform) { return coordinates[0]; } return coordinates; } function _getPixelSpacing(metadata) { if (metadata.PixelSpacing) { return metadata.PixelSpacing; } const functionalGroup = metadata.SharedFunctionalGroupsSequence[0]; const pixelMeasures = functionalGroup.PixelMeasuresSequence[0]; return pixelMeasures.PixelSpacing; } function mapSlideCoord2PixelCoord(options) { // X and Y Offset in Slide Coordinate System if (!('offset' in options)) { throw new Error('Option "offset" is required.'); } if (!Array.isArray(options.offset)) { throw new Error('Option "offset" must be an array.'); } if (options.offset.length !== 2) { throw new Error('Option "offset" must be an array with 2 elements.'); } const offset = options.offset; // Image Orientation Slide with direction cosines for Row and Column direction if (!('orientation' in options)) { throw new Error('Option "orientation" is required.'); } if (!Array.isArray(options.orientation)) { throw new Error('Option "orientation" must be an array.'); } if (options.orientation.length !== 6) { throw new Error('Option "orientation" must be an array with 6 elements.'); } const orientation = options.orientation; // Pixel Spacing along the Row and Column direction if (!('spacing' in options)) { throw new Error('Option "spacing" is required.'); } if (!Array.isArray(options.spacing)) { throw new Error('Option "spacing" must be an array.'); } if (options.spacing.length !== 2) { throw new Error('Option "spacing" must be an array with 2 elements.'); } const spacing = options.spacing; // X and Y coordinate in the Slide Coordinate System if (!('point' in options)) { throw new Error('Option "point" is required.'); } if (!Array.isArray(options.point)) { throw new Error('Option "point" must be an array.'); } if (options.point.length !== 2) { throw new Error('Option "point" must be an array with 2 elements.'); } const point = options.point; const m = [ [orientation[0] * spacing[1], orientation[3] * spacing[0], offset[0]], [orientation[1] * spacing[1], orientation[4] * spacing[0], offset[1]], [0, 0, 1], ]; const mInverted = inv(m); const vSlide = [[point[0]], [point[1]], [1]]; const vImage = multiply(mInverted, vSlide); const row = Number(vImage[1][0].toFixed(4)); const col = Number(vImage[0][0].toFixed(4)); return [col, row]; } |