-
-
Save dannyrb/ed33fbc3e5238eee1160872da2fd6eaa to your computer and use it in GitHub Desktop.
DICOM Overlays
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const overlayGroupTags = []; | |
for (var i = 0; i <= (0x00ee0000); i += (0x00020000)) { | |
overlayGroupTags.push((0x60000000 + i)); | |
} | |
imageRendered(e) { | |
const eventData = e.detail; | |
if (eventData && eventData.image && eventData.image.$presentationStateDataSet) { | |
const context = eventData.canvasContext.canvas.getContext('2d'); | |
context.save(); | |
const imageWidth = Math.abs(eventData.viewport.displayedArea.brhc.x - eventData.viewport.displayedArea.tlhc.x) * eventData.viewport.displayedArea.columnPixelSpacing; | |
const imageHeight = Math.abs(eventData.viewport.displayedArea.brhc.y - eventData.viewport.displayedArea.tlhc.y) * eventData.viewport.displayedArea.rowPixelSpacing; | |
const presentationState = eventData.image.$presentationStateDataSet; | |
if (!presentationState) { | |
return; | |
} | |
_.each(overlayGroupTags, function(overlayGroupNumber) { | |
const activationLayer = Overlays.getOverlayActivationLayer(presentationState, overlayGroupNumber) || Overlays.getOverlayActivationLayer(eventData.image.dataSet, overlayGroupNumber); | |
if (!activationLayer) { | |
return; | |
} | |
const overlay = Overlays.extractOverlay(presentationState, overlayGroupNumber) || Overlays.extractOverlay(eventData.image.dataSet, overlayGroupNumber, eventData.image); | |
if (overlay) { | |
const layerCanvas = document.createElement('canvas'); | |
layerCanvas.width = imageWidth; | |
layerCanvas.height = imageHeight; | |
const layerContext = layerCanvas.getContext('2d'); | |
const transform = cornerstone.internal.getTransform(eventData.enabledElement); | |
layerContext.setTransform(transform.m[0], transform.m[1], transform.m[2], transform.m[3], transform.m[4], transform.m[5]); | |
layerContext.save(); | |
layerContext.setTransform(1, 0, 0, 1, 0, 0); | |
layerContext.fillStyle = Theme.getProperty(Theme.VIEWPORT_TEXT); | |
if (overlay) { | |
if (overlay.type === 'R') { | |
layerContext.fillRect(0, 0, layerCanvas.width, layerCanvas.height); | |
layerContext.globalCompositeOperation = 'xor'; | |
} | |
let i = 0; | |
for (var y = 0; y < overlay.height; y++) { | |
for (var x = 0; x < overlay.width; x++) { | |
const pixel = overlay.data[i++]; | |
if (pixel > 0) { | |
layerContext.fillRect(x, y, 1, 1); | |
} | |
} | |
} | |
} | |
layerContext.restore(); | |
context.drawImage(layerCanvas, 0, 0); | |
} | |
}); | |
context.restore(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//import Tag from './Tag'; DICOM Tag dictionary | |
class Overlays { | |
constructor() { | |
const overlayGroupTags = []; | |
for (var i = 0; i <= (0x00ee0000); i += (0x00020000)) { | |
overlayGroupTags.push((0x60000000 + i)); | |
} | |
this.OVERLAY_GROUP_TAGS = overlayGroupTags; | |
//AutoBind(this); This is a utility for injecting the 'this' keyword into every method | |
} | |
getOverlayWidth(dataSet, overlayNumber) { | |
return dataSet.uint16(Tag.toHexString(Tag.OverlayColumns | (overlayNumber &= 0x60FF0000))); | |
} | |
getOverlayHeight(dataSet, overlayNumber) { | |
return dataSet.uint16(Tag.toHexString(Tag.OverlayRows | (overlayNumber &= 0x60FF0000))); | |
} | |
getOverlayActivationLayer(dataSet, overlayNumber) { | |
return dataSet.string(Tag.toHexString(Tag.OverlayActivationLayer | (overlayNumber &= 0x60FF0000))); | |
} | |
isOverlay(imageIndex) { | |
return ((imageIndex & 0x60000000) === 0x60000000) && (imageIndex & 0x9F010000) === 0; | |
} | |
extractFrameNumber(imageIndex) { | |
const {isOverlay} = this; | |
if (isOverlay(imageIndex)) { | |
return imageIndex & 0xFFFF; | |
} | |
return 0; | |
} | |
extractOverlay(dataSet, overlayNumber, image) { | |
const {isOverlay, extractFrameNumber, getOverlayHeight, getOverlayWidth, getOverlayActivationLayer} = this; | |
if (!isOverlay(overlayNumber)) { | |
return undefined; | |
} | |
const frameNumber = extractFrameNumber(overlayNumber); | |
overlayNumber = overlayNumber & 0x60FE0000; | |
const rows = getOverlayHeight(dataSet, overlayNumber); | |
const columns = getOverlayWidth(dataSet, overlayNumber); | |
const bitPosition = dataSet.uint16(Tag.toHexString(overlayNumber | Tag.OverlayBitPosition)); | |
let data; | |
if (bitPosition === 0) { | |
const overlayData = dataSet.elements[Tag.toHexString(overlayNumber | Tag.OverlayData)]; | |
if (overlayData) { | |
const length = rows * columns * 8; | |
data = []; | |
for (var i = 0; i < overlayData.length; i++) { | |
for (var k = 0; k < 8; k++) { | |
const byte_as_int = dataSet.byteArray[overlayData.dataOffset + i]; | |
data[i * 8 + k] = (byte_as_int >> k) & 0b1; | |
} | |
} | |
} | |
} else if (image) { | |
const bitsAllocated = dataSet.int16(Tag.toHexString(overlayNumber | Tag.OverlayBitsAllocated)); | |
const pixelData = image.getPixelData(); | |
data = []; | |
const bit = (1 << bitPosition); | |
var j = 0; | |
for (var y = 0; y < rows; y++) { | |
for (var x = 0; x < columns; x++) { | |
const pixel = pixelData[j]; | |
if ((pixel & bit) != 0) { | |
data[j] = 1; | |
} else { | |
data[j] = 0; | |
} | |
j++; | |
} | |
} | |
} | |
if (data) { | |
return { | |
x : dataSet.int16(Tag.toHexString(overlayNumber | Tag.OverlayOrigin), 1) - 1, | |
y : dataSet.int16(Tag.toHexString(overlayNumber | Tag.OverlayOrigin), 0) - 1, | |
width : columns, | |
height : rows, | |
data : data, | |
type : dataSet.string(Tag.toHexString(overlayNumber | Tag.OverlayType)), | |
layer : getOverlayActivationLayer(dataSet, overlayNumber) | |
}; | |
} | |
} | |
} | |
export default new Overlays(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment