[OHIF-Viewers]医疗数字阅片-医学影像-cornerstone-core-Cornerstone.js-Cornerstone Examples-基石实例-下
CT Image with Window presets
This is an example of displaying a ct image along with buttons to set ww/wc presets. You can manually adjust the ww/wc by dragging the left mouse button
这是一个显示ct图像以及设置ww/wc预设的按钮的示例。可以通过拖动鼠标左键手动调整ww/wc
代码语言:javascript复制<!-- include special code for these examples which provides images -->
<script src="../exampleImageIdLoaderCt.js"></script>
<script>
// image enable the dicomImage element
const element = document.getElementById('dicomImage');
cornerstone.enable(element);
// load and display the image
const imageId = 'ctexample://1';
cornerstone.loadImage(imageId).then(function(image) {
cornerstone.displayImage(element, image);
const viewport = cornerstone.getViewport(element);
document.getElementById('window').textContent = "WW/WC:" Math.round(viewport.voi.windowWidth)
"/" Math.round(viewport.voi.windowCenter);
// Add event handler for the ww/wc presets
document.getElementById('softTissue').addEventListener('click', function() {
let viewport = cornerstone.getViewport(element);
viewport.voi.windowWidth = 400;
viewport.voi.windowCenter = 20;
cornerstone.setViewport(element, viewport);
document.getElementById('window').textContent = "WW/WC:" Math.round(viewport.voi.windowWidth)
"/" Math.round(viewport.voi.windowCenter);
});
document.getElementById('lung').addEventListener('click', function() {
let viewport = cornerstone.getViewport(element);
viewport.voi.windowWidth = 1600;
viewport.voi.windowCenter = -600;
cornerstone.setViewport(element, viewport);
document.getElementById('window').textContent = "WW/WC:" Math.round(viewport.voi.windowWidth)
"/" Math.round(viewport.voi.windowCenter);
});
document.getElementById('bone').addEventListener('click', function() {
let viewport = cornerstone.getViewport(element);
viewport.voi.windowWidth = 2000;
viewport.voi.windowCenter = 300;
cornerstone.setViewport(element, viewport);
document.getElementById('window').textContent = "WW/WC:" Math.round(viewport.voi.windowWidth)
"/" Math.round(viewport.voi.windowCenter);
});
// add event handlers to mouse move to adjust window/center
element.addEventListener('mousedown', function (e) {
let lastX = e.pageX;
let lastY = e.pageY;
function mouseMoveHandler(e) {
const deltaX = e.pageX - lastX;
const deltaY = e.pageY - lastY;
lastX = e.pageX;
lastY = e.pageY;
let viewport = cornerstone.getViewport(element);
viewport.voi.windowWidth = (deltaX / viewport.scale);
viewport.voi.windowCenter = (deltaY / viewport.scale);
cornerstone.setViewport(element, viewport);
document.getElementById('window').textContent = "WW/WC:" Math.round(viewport.voi.windowWidth)
"/" Math.round(viewport.voi.windowCenter);
}
function mouseUpHandler() {
document.removeEventListener('mousemove', mouseMoveHandler);
document.removeEventListener('mouseup', mouseUpHandler);
}
document.addEventListener('mousemove', mouseMoveHandler);
document.addEventListener('mouseup', mouseUpHandler);
});
});
</script>
Non-square pixels
This example shows an image with non square pixels. The image is 128x256 and has a column and row pixel spacing of 1.0/0.5 respectively. The image will display a square if non square pixels is being applied properly or a tall rectangle if not.
这个例子显示了一个非正方形像素的图像。图像为128x256,列像素间距为1.0/0.5。如果非正方形像素被正确应用,图像将显示一个正方形;如果没有,则显示一个高矩形。
代码语言:javascript复制<script>
// Loads an image given an imageId
function loadImage(imageId) {
var width = 128;
var height = 256;
var numPixels = width * height;
var pixelData = new Uint16Array(numPixels);
var index = 0;
// clear image to black
for (var y = 0; y < height; y ) {
for (var x = 0; x < width; x ) {
pixelData[index] = 128;
index ;
}
}
var left = 10;
var top = 20;
var squareWidth = 50;
var squareHeight = 100;
for (var row = top; row < top squareHeight; row ) {
var rowOffset = row * width;
pixelData[rowOffset left] = 255;
pixelData[rowOffset left squareWidth] = 255;
}
var topRowOffset = top * width;
var bottomRowOffset = (top squareHeight) * width;
for (var column = left; column < left squareWidth; column ) {
pixelData[topRowOffset column] = 255;
pixelData[bottomRowOffset column] = 255;
}
function getPixelData()
{
return pixelData;
}
var image = {
imageId: imageId,
minPixelValue: 0,
maxPixelValue: 255,
slope: 1.0,
intercept: 0,
windowCenter: 127,
windowWidth: 256,
render: cornerstone.renderGrayscaleImage,
getPixelData: getPixelData,
rows: height,
columns: width,
height: height,
width: width,
color: false,
columnPixelSpacing: 1.0,
rowPixelSpacing: 0.5,
invert: false,
sizeInBytes: width * height * 2
};
// Create a Promise, resolve it with the image object we just created and return the
// Promise to cornerstone. Cornerstone will get the image object by calling then() on the
// Promise. An optional function can be provided to allow the image loader to cancel a request.
return {
promise: new Promise((resolve) => {
resolve(image);
}),
cancelFn: undefined
};
}
cornerstone.registerImageLoader('myImageLoader', loadImage);
// image enable the element
const element = document.getElementById('dicomImage');
cornerstone.enable(element);
// load and display the image
const imageId = "myImageLoader://1";
cornerstone.loadImage(imageId).then(function(image) {
element.addEventListener("cornerstoneimagerendered", function(e) {
const eventData = e.detail;
// reset to identity matrix
eventData.canvasContext.setTransform(1, 0, 0, 1, 0, 0);
var context = eventData.canvasContext;
context.beginPath();
context.strokeStyle = 'white';
context.lineWidth = 0;
var topLeft = cornerstone.pixelToCanvas(element, {x:30, y:30});
var bottomRight = cornerstone.pixelToCanvas(element, {x:40, y:40});
context.rect(topLeft.x, topLeft.y, bottomRight.x-topLeft.x, bottomRight.y - topLeft.y);
context.stroke();
context.fillStyle = "white";
context.font = "14px Arial";
context.fillText("Tumor Here", topLeft.x, topLeft.y);
});
cornerstone.displayImage(element, image);
});
// Add event handlers to flip or rotate the image
document.getElementById('hFlip').addEventListener('click', function (e) {
var viewport = cornerstone.getViewport(element);
viewport.hflip = !viewport.hflip;
cornerstone.setViewport(element, viewport);
});
document.getElementById('vFlip').addEventListener('click', function (e) {
var viewport = cornerstone.getViewport(element);
viewport.vflip = !viewport.vflip;
cornerstone.setViewport(element, viewport);
});
document.getElementById('lRotate').addEventListener('click', function (e) {
var viewport = cornerstone.getViewport(element);
viewport.rotation-=90;
cornerstone.setViewport(element, viewport);
});
document.getElementById('rRotate').addEventListener('click', function (e) {
var viewport = cornerstone.getViewport(element);
viewport.rotation =90;
cornerstone.setViewport(element, viewport);
});
document.getElementById('reset').addEventListener('click', function (e) {
cornerstone.reset(element);
});
element.addEventListener('mousemove', function(event) {
const pixelCoords = cornerstone.pageToPixel(element, event.pageX, event.pageY);
const pt = cornerstone.pixelToCanvas(element, pixelCoords);
document.getElementById('coords').textContent = "page=(" event.pageX ", " event.pageY "); pixel=(" pixelCoords.x.toFixed(1) ", " pixelCoords.y.toFixed(1) '); canvas=(' pt.x.toFixed(1) ', ' pt.y.toFixed(1) ')';
});
// add event handlers to pan image on mouse move
element.addEventListener('mousedown', function (e) {
let lastX = e.pageX;
let lastY = e.pageY;
function mouseMoveHandler(e) {
const deltaX = e.pageX - lastX;
const deltaY = e.pageY - lastY;
lastX = e.pageX;
lastY = e.pageY;
const viewport = cornerstone.getViewport(element);
viewport.translation.x = (deltaX / viewport.scale);
viewport.translation.y = (deltaY / viewport.scale);
cornerstone.setViewport(element, viewport);
}
function mouseUpHandler() {
document.removeEventListener('mousemove', mouseMoveHandler);
document.removeEventListener('mouseup', mouseUpHandler);
}
document.addEventListener('mousemove', mouseMoveHandler);
document.addEventListener('mouseup', mouseUpHandler);
});
const mouseWheelEvents = ['mousewheel', 'DOMMouseScroll'];
mouseWheelEvents.forEach(function(eventType) {
element.addEventListener(eventType, function (e) {
// Firefox e.detail > 0 scroll back, < 0 scroll forward
// chrome/safari e.wheelDelta < 0 scroll back, > 0 scroll forward
let viewport = cornerstone.getViewport(element);
if (e.wheelDelta < 0 || e.detail > 0) {
viewport.scale -= 0.25;
} else {
viewport.scale = 0.25;
}
cornerstone.setViewport(element, viewport);
// Prevent page from scrolling
return false;
});
});
</script>
Color Images
This example shows how cornerstone can display color images. It uses a custom image loader that returns a color image
这个例子展示了基石如何显示彩色图像。它使用一个自定义的图像加载器返回一个彩色图像
代码语言:javascript复制<script>
const canvas = document.createElement('canvas');
// Loads an image given an imageId
function loadImage(imageId) {
const width = 256;
const height = 256;
canvas.width = width;
canvas.height = height;
const canvasContext = canvas.getContext('2d');
const imageData = canvasContext.createImageData(width, height);
const pixelData = imageData.data;
const rnd = Math.round(Math.random() * 255);
let index = 0;
for (let y = 0; y < height; y ) {
for (let x = 0; x < width; x ) {
pixelData[index ] = (x rnd) % 256; // RED
pixelData[index ] = 0; // GREEN
pixelData[index ] = 0; // BLUE
pixelData[index ] = 255; // ALPHA
}
}
canvasContext.putImageData(imageData, 0, 0);
function getPixelData() {
return pixelData;
}
function getImageData() {
return imageData;
}
function getCanvas() {
return canvas;
}
const image = {
imageId: imageId,
minPixelValue: 0,
maxPixelValue: 255,
slope: 1.0,
intercept: 0,
windowCenter: 128,
windowWidth: 255,
render: cornerstone.renderColorImage,
getPixelData: getPixelData,
getImageData: getImageData,
getCanvas: getCanvas,
rows: height,
columns: width,
height: height,
width: width,
color: true,
columnPixelSpacing: 1.0,
rowPixelSpacing: 1.0,
invert: false,
sizeInBytes : width * height * 4
};
return {
promise: new Promise((resolve) => resolve(image)),
cancelFn: undefined
};
}
cornerstone.registerImageLoader('colorImageLoader', loadImage);
// image enable the element
const element = document.getElementById('dicomImage');
cornerstone.enable(element);
function onImageRendered(e) {
const eventData = e.detail;
document.getElementById('renderTime').textContent = "Render Time:" eventData.renderTimeInMs " ms";
}
element.addEventListener('cornerstoneimagerendered', onImageRendered);
// load image and display it
const imageId = "colorImageLoader://1";
cornerstone.loadImage(imageId).then(function(image) {
cornerstone.displayImage(element, image);
});
// add event handlers to mouse move to adjust window/center
element.addEventListener('mousedown', function (e) {
let lastX = e.pageX;
let lastY = e.pageY;
function mouseMoveHandler(e) {
const deltaX = e.pageX - lastX;
const deltaY = e.pageY - lastY;
lastX = e.pageX;
lastY = e.pageY;
let viewport = cornerstone.getViewport(element);
viewport.voi.windowWidth = (deltaX / viewport.scale);
viewport.voi.windowCenter = (deltaY / viewport.scale);
cornerstone.setViewport(element, viewport);
}
function mouseUpHandler() {
document.removeEventListener('mousemove', mouseMoveHandler);
document.removeEventListener('mouseup', mouseUpHandler);
}
document.addEventListener('mousemove', mouseMoveHandler);
document.addEventListener('mouseup', mouseUpHandler);
});
</script>
Image Cache
This example shows how the image cache works
这个例子展示了图像缓存的工作原理
代码语言:javascript复制<script>
const cacheInfo = cornerstone.imageCache.getCacheInfo();
document.getElementById('maxCacheSize').value = cacheInfo.maximumSizeInBytes;
document.getElementById('apply').addEventListener('click', function () {
const maxSizeInBytes = parseFloat(document.getElementById('maxCacheSize').value);
cornerstone.imageCache.setMaximumSizeBytes(maxSizeInBytes);
});
document.getElementById('purge').addEventListener('click', function () {
cornerstone.imageCache.purgeCache();
document.getElementById('currentCacheSize').value = cacheInfo.cacheSizeInBytes;
document.getElementById('numImagesCached').value = cacheInfo.numberOfImagesCached;
});
let imageNum = 2;
document.getElementById('addImage').addEventListener('click', function() {
const imageId = "colorImageLoader://" imageNum ;
cornerstone.loadAndCacheImage(imageId).then(function(image) {
const cacheInfo = cornerstone.imageCache.getCacheInfo();
cornerstone.displayImage(element, image);
document.getElementById('currentCacheSize').value = cacheInfo.cacheSizeInBytes;
document.getElementById('numImagesCached').value = cacheInfo.numberOfImagesCached;
});
});
document.getElementById('changeImageSize').addEventListener('click', function() {
const imageId = "colorImageLoader://1";
cornerstone.imageCache.changeImageIdCacheSize(imageId, 512 * 1024);
});
var canvas = document.createElement('canvas');
// Loads an image given an imageId
function loadImage (imageId) {
var width = 256;
var height = 256;
canvas.width = width;
canvas.height = height;
var canvasContext = canvas.getContext('2d');
var imageData = canvasContext.createImageData(width, height);
var pixelData = imageData.data;
var index = 0;
var rnd = Math.round(Math.random() * 255);
for (var y = 0; y < height; y ) {
for (var x = 0; x < width; x ) {
pixelData[index ] = (x rnd) % 256; // RED
pixelData[index ] = 0; // GREEN
pixelData[index ] = 0; // BLUE
pixelData[index ] = 255; // ALPHA
}
}
canvasContext.putImageData(imageData, 0, 0);
function getPixelData() {
return pixelData;
}
function getImageData() {
return imageData;
}
function getCanvas() {
return canvas;
}
var image = {
imageId: imageId,
minPixelValue: 0,
maxPixelValue: 255,
slope: 1.0,
intercept: 0,
windowCenter: 127,
windowWidth: 256,
getPixelData: getPixelData,
getImageData: getImageData,
getCanvas: getCanvas,
render : cornerstone.renderColorImage,
rows: height,
columns: width,
height: height,
width: width,
color: true,
columnPixelSpacing: 1.0,
rowPixelSpacing: 1.0,
invert: false,
sizeInBytes : width * height * 4
};
return {
promise: new Promise((resolve) => resolve(image)),
cancelFn: undefined
}
}
cornerstone.registerImageLoader('colorImageLoader', loadImage);
// image enable the element
const element = document.getElementById('dicomImage');
cornerstone.enable(element);
function onImageRendered(e) {
const eventData = e.detail;
document.getElementById('renderTime').textContent = "Render Time:" eventData.renderTimeInMs " ms";
}
element.addEventListener('cornerstoneimagerendered', onImageRendered);
// load image and display it
const imageId = "colorImageLoader://1";
cornerstone.loadAndCacheImage(imageId).then(function(image) {
cornerstone.displayImage(element, image);
// add event handlers to mouse move to adjust window/center
element.addEventListener('mousedown', function (e) {
let lastX = e.pageX;
let lastY = e.pageY;
function mouseMoveHandler(e) {
const deltaX = e.pageX - lastX;
const deltaY = e.pageY - lastY;
lastX = e.pageX;
lastY = e.pageY;
let viewport = cornerstone.getViewport(element);
viewport.voi.windowWidth = (deltaX / viewport.scale);
viewport.voi.windowCenter = (deltaY / viewport.scale);
cornerstone.setViewport(element, viewport);
}
function mouseUpHandler() {
document.removeEventListener('mousemove', mouseMoveHandler);
document.removeEventListener('mouseup', mouseUpHandler);
}
document.addEventListener('mousemove', mouseMoveHandler);
document.addEventListener('mouseup', mouseUpHandler);
});
});
</script>
Dynamic Image
This example shows how to integrate dynamically generated images with cornerstone. A dynamic image generator is one that can produce new images on the client side. This could be used to do image fusion as well as MPR or Volume Rendering.
这个例子展示了如何将动态生成的图像与基石集成。动态图像生成器可以在客户端生成新图像。这可以用于图像融合,以及MPR或体绘制。
代码语言:javascript复制<script>
function getPixelData() {
const width = 256;
const height = 256;
const numPixels = width * height;
const pixelData = new Uint16Array(numPixels);
let index = 0;
for (let y = 0; y < height; y ) {
for (let x = 0; x < width; x ) {
pixelData[index] = ((x) % 256) * this.data.opacity;
index ;
}
}
return pixelData;
}
const dynamicImage = {
imageId: "notneeded",
minPixelValue: 0,
maxPixelValue: 255,
slope: 1.0,
intercept: 0,
windowCenter: 127,
windowWidth: 256,
render: cornerstone.renderGrayscaleImage,
getPixelData: getPixelData,
rows: 256,
columns: 256,
height: 256,
width: 256,
color: false,
columnPixelSpacing: 1.0,
rowPixelSpacing: 1.0,
invert: false,
sizeInBytes: 256 * 256 * 2,
data: {
opacity: 0.5
}
};
// image enable the element
const element = document.getElementById('dicomImage');
cornerstone.enable(element);
cornerstone.displayImage(element, dynamicImage);
document.getElementById('opacity25').addEventListener('click', function () {
dynamicImage.data.opacity = .25;
cornerstone.updateImage(element, true);
});
document.getElementById('opacity75').addEventListener('click', function () {
dynamicImage.data.opacity = .75;
cornerstone.updateImage(element, true);
});
</script>
Flip and Rotate
This is an example of image flips and rotations In this example,the image can be flipped (Horizontal/Vertical) or rotated (Clockwise/Anti-clockwise)
这是一个图像翻转和旋转的示例
在本例中,图像可以翻转(水平/垂直)或旋转(顺时针/逆时针)
代码语言:javascript复制<!-- include special code for these examples which provides images -->
<script src="../exampleImageIdLoader.js"></script>
<script>
// image enable the dicomImage element
const element = document.getElementById('dicomImage');
cornerstone.enable(element);
//load the image and display it
const imageId = 'example://1';
cornerstone.loadImage(imageId).then(function(image) {
cornerstone.displayImage(element, image);
});
// Add event handlers to flip or rotate the image
document.getElementById('hFlip').addEventListener('click', function (e) {
const viewport = cornerstone.getViewport(element);
viewport.hflip = !viewport.hflip;
cornerstone.setViewport(element, viewport);
});
document.getElementById('vFlip').addEventListener('click', function (e) {
const viewport = cornerstone.getViewport(element);
viewport.vflip = !viewport.vflip;
cornerstone.setViewport(element, viewport);
});
document.getElementById('lRotate').addEventListener('click', function (e) {
const viewport = cornerstone.getViewport(element);
viewport.rotation-=90;
cornerstone.setViewport(element, viewport);
});
document.getElementById('rRotate').addEventListener('click', function (e) {
const viewport = cornerstone.getViewport(element);
viewport.rotation =90;
cornerstone.setViewport(element, viewport);
});
document.getElementById('reset').addEventListener('click', function (e) {
cornerstone.reset(element);
});
element.addEventListener('mousemove', function(event) {
const pixelCoords = cornerstone.pageToPixel(element, event.pageX, event.pageY);
document.getElementById('coords').textContent = "pageX=" event.pageX ", pageY=" event.pageY ", pixelX=" pixelCoords.x ", pixelY=" pixelCoords.y;
});
</script>
Modality LUT and VOI LUT
This example shows the application of Modality LUT and VOI LUT to the image display pipeline
这个例子展示了模态LUT和VOI LUT在图像显示管道中的应用
代码语言:javascript复制<script>
// create an inverting lut
var modalityLUT = {
id : '1',
firstValueMapped: 0,
numBitsPerEntry : 8,
lut: []
};
for(let i=0; i < 256; i ) {
modalityLUT.lut[i] = 255 - i;
}
var voiLUT = {
id : '1',
firstValueMapped: 0,
numBitsPerEntry : 8,
lut: []
};
for(let i=0; i < 256; i ) {
voiLUT.lut[i] = i / 2 127;
}
//create VOI Presets
var presetVoiLUT = {
id: '2',
firstValueMapped: 0,
numBitsPerEntry: 8,
lut: []
};
for (let i = 0; i < 256; i ) {
presetVoiLUT.lut[i] = Math.floor(Math.random() * 256);
}
var voiPresets = [{ ww: 200, wc: 50 }, { ww: 100, wc: 127 }, { voiLUT: presetVoiLUT }];
// Loads an image given an imageId
function loadImage(imageId) {
var width = 256;
var height = 256;
var numPixels = width * height;
var pixelData = new Uint16Array(numPixels);
var index = 0;
var rnd = 0;// Math.round(Math.random() * 255);
for (let y = 0; y < height; y ) {
for (let x = 0; x < width; x ) {
pixelData[index] = (x rnd) % 256;
index ;
}
}
function getPixelData()
{
return pixelData;
}
var image = {
imageId: imageId,
minPixelValue: 0,
maxPixelValue: 255,
slope: 1.0,
intercept: 0,
windowCenter: 127,
windowWidth: 256,
render: cornerstone.renderGrayscaleImage,
getPixelData: getPixelData,
rows: height,
columns: width,
height: height,
width: width,
color: false,
columnPixelSpacing: 1.0,
rowPixelSpacing: 1.0,
invert: false,
sizeInBytes: width * height * 2
};
return {
promise: new Promise((resolve) => resolve(image)),
cancelFn: undefined
};
}
cornerstone.registerImageLoader('myImageLoader', loadImage);
// image enable the element
const element = document.getElementById('dicomImage');
cornerstone.enable(element);
// load the image and display it
const imageId = 'myImageLoader://1';
cornerstone.loadImage(imageId).then(function(image) {
cornerstone.displayImage(element, image);
let viewport = cornerstone.getViewport(element);
viewport.voi.voiPresets = voiPresets;
cornerstone.setViewport(element, viewport);
});
document.getElementById('toggleModalityLUT').addEventListener('click', function() {
const applyModalityLUT = document.getElementById('toggleModalityLUT').checked;
console.log('applyModalityLUT=', applyModalityLUT);
let viewport = cornerstone.getViewport(element);
if(applyModalityLUT) {
viewport.modalityLUT = modalityLUT;
} else {
viewport.modalityLUT = undefined;
}
cornerstone.setViewport(element, viewport);
});
document.getElementById('toggleVOILUT').addEventListener('click', function() {
const applyVOILUT = document.getElementById('toggleVOILUT').checked;
console.log('applyVOILUT=', applyVOILUT);
let viewport = cornerstone.getViewport(element);
if(applyVOILUT) {
viewport.voiLUT = voiLUT;
} else {
viewport.voiLUT = undefined;
}
document.getElementById('selectPreset').value = -1;
cornerstone.setViewport(element, viewport);
});
document.getElementById('selectPreset').addEventListener("change", function () {
let selectedIndex = parseInt(document.getElementById('selectPreset').value, 10);
let image = cornerstone.getImage(element);
let viewport = cornerstone.getViewport(element);
if (selectedIndex >= 0 && selectedIndex < voiPresets.length) {
let voiPreset = voiPresets[selectedIndex];
//keep old values as a state since user might only pass the voiLUT
viewport.voi.windowWidth = (voiPreset.ww === undefined) ? viewport.voi.windowWidth : voiPreset.ww;
viewport.voi.windowCenter = (voiPreset.wc === undefined) ? viewport.voi.windowCenter : voiPreset.wc;
//this always apply
viewport.voiLUT = voiPreset.voiLUT;
cornerstone.setViewport(element, viewport);
document.getElementById('toggleVOILUT').checked = false;
}
else {
resetVoiLUT();
}
});
document.getElementById('resetVOI').addEventListener("click", function () {
resetVoiLUT();
});
function resetVoiLUT() {
let viewport = cornerstone.getViewport(element);
document.getElementById('selectPreset').value = -1;
document.getElementById('toggleVOILUT').checked = false;
viewport.voiLUT = undefined;
viewport.voi.windowWidth = undefined;
viewport.voi.windowCenter = undefined;
cornerstone.setViewport(element, viewport);
}
</script>
All features (scroll, zoom, pan, window/level, html overlays, resize, invert, interpolation)
This is an example of interactive series scroll, pan, zoom and window/level with HTML based overlays. Controls:
- Left click drag - window/level
- Middle Mouse button drag - pan
- Right click drag - zoom
- Mouse wheel - scroll images
这是一个交互式系列滚动、平移、缩放和基于HTML的覆盖的窗口/级别的示例。
控制:
左键单击拖动-窗口/标高
鼠标中键拖动-平移
右键单击拖动-缩放
鼠标滚轮-滚动图像
代码语言:javascript复制<script>
const imageIds = [
'example://1',
'example://2'
];
let currentImageIndex = 0;
// updates the image display
function updateTheImage(imageIndex) {
return cornerstone.loadAndCacheImage(imageIds[imageIndex]).then(function(image) {
currentImageIndex = imageIndex;
const viewport = cornerstone.getViewport(element);
cornerstone.displayImage(element, image, viewport);
});
}
// image enable the element
const element = document.getElementById('dicomImage');
cornerstone.enable(element);
// setup handlers before we display the image
function onImageRendered(e) {
const eventData = e.detail;
// set the canvas context to the image coordinate system
cornerstone.setToPixelCoordinateSystem(eventData.enabledElement, eventData.canvasContext);
// NOTE: The coordinate system of the canvas is in image pixel space. Drawing
// to location 0,0 will be the top left of the image and rows,columns is the bottom
// right.
const context = eventData.canvasContext;
context.beginPath();
context.strokeStyle = 'white';
context.lineWidth = .5;
context.rect(128, 90, 50, 60);
context.stroke();
context.fillStyle = "white";
context.font = "6px Arial";
context.fillText("Tumor Here", 128, 85);
document.getElementById('topright').textContent = "Render Time:" eventData.renderTimeInMs " ms";
document.getElementById('bottomleft').textContent = "WW/WL:" Math.round(eventData.viewport.voi.windowWidth) "/" Math.round(eventData.viewport.voi.windowCenter);
document.getElementById('bottomright').textContent = "Zoom:" eventData.viewport.scale.toFixed(2);
}
element.addEventListener('cornerstoneimagerendered', onImageRendered);
// load and display the image
const imagePromise = updateTheImage(0);
// add handlers for mouse events once the image is loaded.
imagePromise.then(function() {
// add event handlers to pan image on mouse move
element.addEventListener('mousedown', function (e) {
let lastX = e.pageX;
let lastY = e.pageY;
const mouseButton = e.which;
function mouseMoveHandler(e) {
const deltaX = e.pageX - lastX;
const deltaY = e.pageY - lastY;
lastX = e.pageX;
lastY = e.pageY;
if (mouseButton === 1) {
let viewport = cornerstone.getViewport(element);
viewport.voi.windowWidth = (deltaX / viewport.scale);
viewport.voi.windowCenter = (deltaY / viewport.scale);
cornerstone.setViewport(element, viewport);
} else if (mouseButton === 2) {
let viewport = cornerstone.getViewport(element);
viewport.translation.x = (deltaX / viewport.scale);
viewport.translation.y = (deltaY / viewport.scale);
cornerstone.setViewport(element, viewport);
} else if (mouseButton === 3) {
let viewport = cornerstone.getViewport(element);
viewport.scale = (deltaY / 100);
cornerstone.setViewport(element, viewport);
}
}
function mouseUpHandler() {
document.removeEventListener('mouseup', mouseUpHandler);
document.removeEventListener('mousemove', mouseMoveHandler);
}
document.addEventListener('mousemove', mouseMoveHandler);
document.addEventListener('mouseup', mouseUpHandler);
});
const mouseWheelEvents = ['mousewheel', 'DOMMouseScroll'];
mouseWheelEvents.forEach(function(eventType) {
element.addEventListener(eventType, function (e) {
// Firefox e.detail > 0 scroll back, < 0 scroll forward
// chrome/safari e.wheelDelta < 0 scroll back, > 0 scroll forward
if (e.wheelDelta < 0 || e.detail > 0) {
if (currentImageIndex === 0) {
updateTheImage(1);
}
} else {
if (currentImageIndex === 1) {
updateTheImage(0);
}
}
// Prevent page from scrolling
return false;
});
});
// Add event handler to the ww/wc apply button
document.getElementById('x256').addEventListener('click', function (e) {
element.style.width = '256px';
element.style.height = '256px';
cornerstone.resize(element);
});
document.getElementById('x512').addEventListener('click', function (e) {
element.style.width = '512px';
element.style.height = '512px';
cornerstone.resize(element);
});
document.getElementById('invert').addEventListener('click', function (e) {
const viewport = cornerstone.getViewport(element);
viewport.invert = !viewport.invert;
cornerstone.setViewport(element, viewport);
});
document.getElementById('interpolation').addEventListener('click', function (e) {
const viewport = cornerstone.getViewport(element);
viewport.pixelReplication = !viewport.pixelReplication;
cornerstone.setViewport(element, viewport);
});
document.getElementById('hflip').addEventListener('click', function (e) {
const viewport = cornerstone.getViewport(element);
viewport.hflip = !viewport.hflip;
cornerstone.setViewport(element, viewport);
});
document.getElementById('vflip').addEventListener('click', function (e) {
const viewport = cornerstone.getViewport(element);
viewport.vflip = !viewport.vflip;
cornerstone.setViewport(element, viewport);
});
document.getElementById('rotate').addEventListener('click', function (e) {
const viewport = cornerstone.getViewport(element);
viewport.rotation = 90;
cornerstone.setViewport(element, viewport);
});
element.addEventListener('mousemove', function(event) {
const pixelCoords = cornerstone.pageToPixel(element, event.pageX, event.pageY);
document.getElementById('coords').textContent = "pageX=" event.pageX ", pageY=" event.pageY ", pixelX=" pixelCoords.x ", pixelY=" pixelCoords.y;
});
});
</script>
Using WebGL Rendering option
This is an example of WebGL use in cornerstone
这是一个WebGL在基石中的使用示例
代码语言:javascript复制<!-- include special code for these examples which provides images -->
<script src="../exampleImageIdLoader.js"></script>
<script>
const element = document.getElementById('dicomImage');
const elementWebGL = document.getElementById('dicomImageWebGL');
// setup handlers before we display the image
function onImageRendered(e) {
const eventData = e.detail;
// set the canvas context to the image coordinate system
cornerstone.setToPixelCoordinateSystem(eventData.enabledElement, eventData.canvasContext);
const parent = eventData.element.parentNode;
parent.querySelector('.renderTime').textContent = "Render Time:" eventData.renderTimeInMs " ms";
parent.querySelector('.wwwc').textContent = "WW/WL:" Math.round(eventData.viewport.voi.windowWidth)
"/" Math.round(eventData.viewport.voi.windowCenter);
}
element.addEventListener('cornerstoneimagerendered', onImageRendered);
elementWebGL.addEventListener('cornerstoneimagerendered', onImageRendered);
const imageId = 'example://1';
cornerstone.enable(element);
cornerstone.loadAndCacheImage(imageId).then(function(image) {
cornerstone.displayImage(element, image);
});
const options = {
renderer: 'webgl'
};
cornerstone.enable(elementWebGL, options);
cornerstone.loadAndCacheImage(imageId).then(function(image) {
cornerstone.displayImage(elementWebGL, image);
});
const elements = [element, elementWebGL];
elements.forEach(function(elem) {
// add event handlers to mouse move to adjust window/center
elem.addEventListener('mousedown', function (e) {
let lastX = e.pageX;
let lastY = e.pageY;
function mouseMoveHandler(e) {
const deltaX = e.pageX - lastX;
const deltaY = e.pageY - lastY;
lastX = e.pageX;
lastY = e.pageY;
let viewport = cornerstone.getViewport(elem);
viewport.voi.windowWidth = (deltaX / viewport.scale);
viewport.voi.windowCenter = (deltaY / viewport.scale);
cornerstone.setViewport(elem, viewport);
}
function mouseUpHandler() {
document.removeEventListener('mousemove', mouseMoveHandler);
document.removeEventListener('mouseup', mouseUpHandler);
}
document.addEventListener('mousemove', mouseMoveHandler);
document.addEventListener('mouseup', mouseUpHandler);
});
});
</script>
False Color Mapping
This example shows you how to use the pre-defined colormaps or create a custom lookup table and use them to create a false color mapping
本示例说明如何使用预定义的颜色图或创建自定义查找表,并使用它们创建错误的颜色映射。
代码语言:javascript复制<script>
// Populate colormap dropdown with all the default ones available
// in cornerstone and also a "Custom" option
function fillColormapsList() {
const dropdown = document.getElementById('colormaps');
const colormapsList = cornerstone.colors.getColormapsList();
const addOption = function(id, name, disabled) {
const option = document.createElement("OPTION");
option.value = id;
option.textContent = name;
option.disabled = !!disabled;
dropdown.append(option);
};
colormapsList.forEach(function(colormapItem) {
addOption(colormapItem.id, colormapItem.name);
});
// Horizontal Line
addOption('', '──────────', true);
addOption('custom', 'Custom');
}
// image enable the dicomImage element
const element = document.getElementById('dicomImage');
cornerstone.enable(element);
const imageId = 'example://1';
// Load the example image and display it
cornerstone.loadImage(imageId).then(function(image) {
cornerstone.displayImage(element, image);
// add event handlers to pan image on mouse move
element.addEventListener('mousedown', function (e) {
let lastX = e.pageX;
let lastY = e.pageY;
const mouseButton = e.which;
function mouseMoveHandler(e) {
const deltaX = e.pageX - lastX;
const deltaY = e.pageY - lastY;
lastX = e.pageX;
lastY = e.pageY;
if (mouseButton === 1) {
let viewport = cornerstone.getViewport(element);
viewport.voi.windowWidth = (deltaX / viewport.scale);
viewport.voi.windowCenter = (deltaY / viewport.scale);
cornerstone.setViewport(element, viewport);
} else if (mouseButton === 2) {
let viewport = cornerstone.getViewport(element);
viewport.translation.x = (deltaX / viewport.scale);
viewport.translation.y = (deltaY / viewport.scale);
cornerstone.setViewport(element, viewport);
} else if (mouseButton === 3) {
let viewport = cornerstone.getViewport(element);
viewport.scale = (deltaY / 100);
cornerstone.setViewport(element, viewport);
}
}
function mouseUpHandler() {
document.removeEventListener('mouseup', mouseUpHandler);
document.removeEventListener('mousemove', mouseMoveHandler);
}
document.addEventListener('mousemove', mouseMoveHandler);
document.addEventListener('mouseup', mouseUpHandler);
});
});
// Dropdown listener to get the new colormap
// selected by the user and update the image
function colormapChanged() {
const viewport = cornerstone.getViewport(element);
const colormapId = document.getElementById('colormaps').value;
let colormap;
// Use selected the first option ("Select...")
if (colormapId === '') {
return;
} else if(colormapId === 'custom') {
colormap = getCustomLookupTable();
} else {
colormap = cornerstone.colors.getColormap(colormapId);
}
viewport.colormap = colormap;
cornerstone.setViewport(element, viewport);
cornerstone.updateImage(element, true);
// Update the colorbar at the top of the image
updateColorbar(colormap);
}
function getCustomLookupTable(minPixelValue, maxPixelValue) {
const colormap = cornerstone.colors.getColormap('myCustomColorMap');
colormap.setNumberOfColors(6);
// You can also use `addColor` but in this case it wouldn't work.
// Any colormap returned by `getColormap` lasts forever (global) and
// calling `addColor` would result in duplicated colors.
colormap.insertColor(0, [188, 252, 201, 255]); // Banana
colormap.insertColor(1, [245, 222, 179, 255]); // Wheat
colormap.insertColor(2, [255, 125, 64, 255]); // Flesh
colormap.insertColor(3, [135, 38, 87, 255]); // Raspberry
colormap.insertColor(4, [227, 206, 87, 255]); // Mint
colormap.insertColor(5, [ 51, 160, 201, 255]); // Peacock
return colormap;
}
// Update the colorbar at the top of the image
function updateColorbar(colormap) {
const lookupTable = colormap.createLookupTable();
const canvas = document.getElementById('colorbar');
const ctx = canvas.getContext('2d');
const height = canvas.height;
const width = canvas.width;
const colorbar = ctx.createImageData(512, 20);
// Set the min and max values then the lookup table
// will be able to return the right color for this range
lookupTable.setTableRange(0, width);
// Update the colorbar pixel by pixel
for(let col = 0; col < width; col ) {
const color = lookupTable.mapValue(col);
for(let row = 0; row < height; row ) {
const pixel = (col row * width) * 4;
colorbar.data[pixel] = color[0];
colorbar.data[pixel 1] = color[1];
colorbar.data[pixel 2] = color[2];
colorbar.data[pixel 3] = color[3];
}
}
ctx.putImageData(colorbar, 0, 0);
}
document.getElementById('colormaps').addEventListener('change', colormapChanged);
fillColormapsList();
</script>
Composite Images
This example shows you how to add and interact with layers.
Viewport Values:
Viewport Scale:
Layer CT Values:
Viewport Scale:
Layer Viewport Scale:
Layer Sync Scale:
Layer PET Values:
Layer Viewport Scale:
Layer Sync Scale:
此示例向您展示了如何添加层并与层交互。
视口值:
视口比例:
层CT值:
视口比例:
图层视口比例:
层同步比例:
层宠物值:
图层视口比例:
层同步比例:
代码语言:javascript复制<!-- include special code for these examples which provides images -->
<script src="../petctImageIdLoader.js"></script>
<script src="../petctMetaDataProvider.js"></script>
<script>
// Enable the dicomImage element
const element = document.getElementById('dicomImage');
cornerstone.enable(element);
// JSON with all layers to be loaded
// The `name` option is used only by this example and
// cornerstone doesn't even know that it exists.
// You can add any option you want to `options` object.
const layers = [{
imageId: 'ct://1',
options: {
name: 'CT'
}
}, {
imageId: 'pet://1',
options: {
name: 'PET',
opacity: 0.7,
viewport: {
colormap: 'hotIron',
voi: {
windowWidth: 30,
windowCenter: 16
}
}
}
}
];
// This is the main function responsible for loading all layers
// This method will wait for all images to be loaded (`loadImages`)
// before adding the layers
function loadLayers() {
loadImages().then(function(images) {
images.forEach(function(image, index) {
const layer = layers[index];
const layerId = cornerstone.addLayer(element, image, layer.options);
cornerstone.updateImage(element);
console.log('Layer ' index ': ' layerId);
});
// Update dropdown size to make all layers name visible
const layersDropdown = document.getElementById('layers');
layersDropdown.size = layers.length;
// Listen to `change` event to set the selected layer as active
layersDropdown.addEventListener('change', function(event) {
const layerId = event.currentTarget.value;
cornerstone.setActiveLayer(element, layerId);
});
});
}
// This method loads the image of each layer and resolve the
// promise only after getting all of them loaded
function loadImages() {
const promises = [];
layers.forEach(function(layer) {
const loadPromise = cornerstone.loadAndCacheImage(layer.imageId);
promises.push(loadPromise);
});
return Promise.all(promises);
}
// Select the right layer in the dropdown
function updateSelectedLayer(layerId) {
const layers = document.getElementById('layers');
const currentLayerId = layers.value;
if(currentLayerId !== layerId) {
layers.value = layerId;
// Trigger a change event
const event = new Event('change');
element.dispatchEvent(event);
}
}
// Listen to `change` event to activate/deactivate the viewport synchronization
document.querySelector('input[name=syncViewports]').addEventListener('change', function(event) {
const enabledElement = cornerstone.getEnabledElement(element);
enabledElement.syncViewports = event.currentTarget.checked;
cornerstone.updateImage(element);
});
document.getElementById('colormaps').addEventListener('change', function() {
const layer = cornerstone.getActiveLayer(element);
layer.viewport.colormap = document.getElementById('colormaps').value;
cornerstone.updateImage(element);
});
// Listen to `change` event to update the opacity of the active layer
document.getElementById("imageOpacity").addEventListener('change', function(event) {
const layer = cornerstone.getActiveLayer(element);
layer.options.opacity = parseFloat(event.currentTarget.value);
cornerstone.updateImage(element);
});
// Listen to `change` event to update the visibility of the active layer
document.querySelector('input[name=visible]').addEventListener('change', function(event) {
const layer = cornerstone.getActiveLayer(element);
layer.options.visible = event.currentTarget.checked;
cornerstone.updateImage(element);
});
// This event will be called every time a layer is added through cornerstone.addLayer
// The layer is added to the dropdown to make it possible to select and interact with it
element.addEventListener('cornerstonelayeradded', function(e) {
const eventData = e.detail;
const layer = cornerstone.getLayer(eventData.element, eventData.layerId);
const layers = document.getElementById('layers');
const layerOption = document.createElement("OPTION");
layerOption.value = layer.layerId;
layerOption.textContent = layer.options.name;
// Set the layer as selected in case its the the first layer to be added
if(layers.childElementCount === 0) {
layerOption.checked = true;
}
layers.appendChild(layerOption);
});
// This event will be called every time cornerstone.setActiveLayer is called
// We need to load the layer properties and update the selected layer in the dropdown
element.addEventListener('cornerstoneactivelayerchanged', function(e) {
const eventData = e.detail;
const layer = cornerstone.getActiveLayer(element);
const colormap = layer.viewport.colormap || '';
const opacity = layer.options.opacity == null ? 1 : layer.options.opacity;
// Restore all properties for the active layer
document.getElementById('imageOpacity').value = opacity;
document.querySelector("input[name=visible]").checked = layer.options.visible === undefined ? true : layer.options.visible;
document.getElementById('colormaps').value = colormap;
updateSelectedLayer(eventData.layerId);
});
// Populate colormap dropdown with all the default ones
function fillColormapsList() {
const dropdown = document.getElementById('colormaps');
const colormapsList = cornerstone.colors.getColormapsList();
const addOption = function(id, name) {
const option = document.createElement("OPTION");
option.value = id;
option.textContent = name;
dropdown.append(option);
};
colormapsList.forEach(function(colormapItem) {
addOption(colormapItem.id, colormapItem.name);
});
}
// add event handlers to pan image on mouse move
element.addEventListener('mousedown', function (e) {
let lastX = e.pageX;
let lastY = e.pageY;
const mouseButton = e.which;
function mouseMoveHandler(e) {
const deltaX = e.pageX - lastX;
const deltaY = e.pageY - lastY;
lastX = e.pageX;
lastY = e.pageY;
if (mouseButton === 1) {
let viewport = cornerstone.getViewport(element);
viewport.voi.windowWidth = (deltaX / viewport.scale);
viewport.voi.windowCenter = (deltaY / viewport.scale);
cornerstone.setViewport(element, viewport);
} else if (mouseButton === 2) {
let viewport = cornerstone.getViewport(element);
viewport.translation.x = (deltaX / viewport.scale);
viewport.translation.y = (deltaY / viewport.scale);
cornerstone.setViewport(element, viewport);
} else if (mouseButton === 3) {
let viewport = cornerstone.getViewport(element);
viewport.scale = (deltaY / 100);
cornerstone.setViewport(element, viewport);
document.getElementById('layerViewportScale').innerText = viewport.scale;
}
const layer1 = cornerstone.getLayers(element)[0];
const layer2 = cornerstone.getLayers(element)[1];
document.getElementById('layer1LayerViewportScale').innerText = layer1.viewport.scale;
document.getElementById('layer2LayerViewportScale').innerText = layer2.viewport.scale;
document.getElementById('layer1LayerSyncScale').innerText = layer1.syncProps.originalScale;
document.getElementById('layer2LayerSyncScale').innerText = layer2.syncProps.originalScale;
}
function mouseUpHandler() {
document.removeEventListener('mouseup', mouseUpHandler);
document.removeEventListener('mousemove', mouseMoveHandler);
}
document.addEventListener('mousemove', mouseMoveHandler);
document.addEventListener('mouseup', mouseUpHandler);
});
const mouseWheelEvents = ['mousewheel', 'DOMMouseScroll'];
mouseWheelEvents.forEach(function(eventType) {
element.addEventListener(eventType, function (e) {
// Firefox e.detail > 0 scroll back, < 0 scroll forward
// chrome/safari e.wheelDelta < 0 scroll back, > 0 scroll forward
let viewport = cornerstone.getViewport(element);
if (e.wheelDelta < 0 || e.detail > 0) {
viewport.scale -= 0.25;
} else {
viewport.scale = 0.25;
}
cornerstone.setViewport(element, viewport);
// Prevent page from scrolling
return false;
});
});
// Start point to load all layers and colormaps and
// also attach a click listener to each tool
loadLayers();
fillColormapsList();
</script>
DICOM Displayed Area Module support
This example demonstrates the IHE Image Display Test 521: Consistent Presentation of Images.
这个例子演示了IHE图像显示测试521:图像的一致表示。
代码语言:javascript复制<!-- include special code for these examples which provides images -->
<script src="../exampleImageIdLoaderRaw.js"></script>
<script>
const viewportOptions = {
scale: 1.0,
translation: {
x: 0,
y: 0
},
invert: false,
pixelReplication: false
};
const element = document.getElementById('dicomImage');
const origElement = document.getElementById('origDicomImage');
loadSelectedCase();
document.getElementById('testCasesSelect').addEventListener('change', () => {
loadSelectedCase();
});
document.getElementById('area-apply').addEventListener("click", function () {
let viewport = cornerstone.getViewport(element);
viewport.displayedArea.tlhc.x = document.getElementById('area-left').value;
viewport.displayedArea.tlhc.y = document.getElementById('area-top').value;
viewport.displayedArea.brhc.x = document.getElementById('area-right').value;
viewport.displayedArea.brhc.y = document.getElementById('area-bottom').value;
viewport.displayedArea.rowPixelSpacing = document.getElementById('row-pixel-spacing').value;
viewport.displayedArea.columnPixelSpacing = document.getElementById('col-pixel-spacing').value;
viewport.displayedArea.presentationSizeMode = document.getElementById('presentation-mode').value;
document.getElementById('test-result').textContent = "";
document.getElementById('test-image').textContent = "";
document.getElementById('test-pState').textContent = "";
cornerstone.setViewport(element, viewport);
});
function loadSelectedCase() {
let imageId = document.getElementById('testCasesSelect').value;
cornerstone.disable(element);
cornerstone.disable(origElement);
cornerstone.enable(element);
cornerstone.enable(origElement);
cornerstone.loadImage(imageId).then(function (image) {
cornerstone.displayImage(element, image, viewportOptions);
cornerstone.displayImage(origElement, image, viewportOptions);
cornerstone.fitToWindow(origElement);
applyTestViewport(element,image);
});
}
function applyTestViewport(element, image) {
if (image.testCase) {
let viewport = cornerstone.getViewport(element);
viewport.displayedArea = image.testCase.displayedArea;
cornerstone.setViewport(element, viewport);
updateUI(element, image, viewport, image.testCase);
}
}
function updateUI(element, image, viewport, testCase) {
if (testCase) {
document.getElementById('test-image').textContent = testCase.image;
document.getElementById('test-pState').textContent = testCase.pState;
document.getElementById('test-result').textContent = testCase.result;
}
document.getElementById('area-left').value = viewport.displayedArea.tlhc.x;
document.getElementById('area-top').value = viewport.displayedArea.tlhc.y;
document.getElementById('area-right').value = viewport.displayedArea.brhc.x;
document.getElementById('area-bottom').value = viewport.displayedArea.brhc.y;
document.getElementById('row-pixel-spacing').value = viewport.displayedArea.rowPixelSpacing;
document.getElementById('col-pixel-spacing').value = viewport.displayedArea.columnPixelSpacing;
document.getElementById('viewerSize').textContent = element.clientWidth 'px X ' element.clientHeight 'px';
document.getElementById('imageSize').textContent = image.width 'px X ' image.height 'px';
document.getElementById('presentation-mode').value = viewport.displayedArea.presentationSizeMode;
}
</script>