cornerstone.js 使用总结

cornerstone.js 使用总结

dicom 简介

dicom(Digital Imaging and Communications in Medicine), 医学影像的一组协议。包含了存储、打印、传输等。具体详细介绍。官网
dicom file, 存储包含病人、检查、影像信息的文件,通常以dcm为扩展名。文件格式
dicom file中由data elements 构成。每一个data element 都有一个tag(xxxx, xxxx)x为十六进制数,vr数据类型,vl数据长度,数据值。dicom tags
例如CT扫描生成的图像,其CT值在tag为(7FE0,0010)的element中。

cornertone-core简介

由javascript编写,构建web端的医学影像平台中的显示环节。对于复杂的web端的医学影像可视化项目,底层可以依赖于cornerstone-core做二维图像渲染。

渲染一张dicom格式的图像

图像信息

对于一张由CT扫描的图像,要准确的渲染成一张数字图像。需要理既以下相关的 data elements

  • Samples per Pixel (0028, 0002), 字面理解每个像素的采样数,灰度图1, RGB图为3
  • Photometric Interpretation (0028, 0004) 颜色空间
  • Planar Configuration (0028,0006), 只对于samples per pixel 大于1时起作用,主要针对rgb图像,其三个颜色成分的存储排列。0: color by pixel, R1-G1-B1-R2-G2-B2…, 1: color By Plane, R1-R2-R3…-G1-G2…-B1-B2…
  • Rows (0028, 0010), 垂直方向上向下采样因子的倍数。简单认为在在图像上一列像素的总数
  • Columns (0028, 0011), 类似Rows,方向为水平方向
  • Bits Allocated (0028,0100) 给每个采样的像素值分配的存储空间
  • Bits Stored (0028,0101) 每个采样的像素值存储时所占的bit数
  • High Bit (0028, 0102) 采样像素的最高有效位
  • Pixel Representation (0028, 0103), 像素值数据类型0:无符号整型, 1:有符号数
  • Pixel Data (7FE0, 0010) 构成图像的像素数据流,从左到右,从上到下。左上角的像素位置记为(1, 1)
  • Slice Thickness(0018, 0050), 切片的层厚
  • Image Position(Patient) (0020, 0032) 图像左上角第一个像素在病人坐标系下的值
  • Image Orientation(Patient) (0020, 0037) 在病人坐标系下,图像的第一行与第一列的方向余弦值。?待图解
  • Pixel Spacing (0028, 0030), 相邻两行(两列)像素在病人坐标系的物理距离值

图像显示

假定dicom file已经解析完成。所有tag数据以key/value形式作为dicom实列的属性。

const result = parseDicomFile(url);
const dicom = {
   
  pixels: result.pixelsData
  rows: result.rows
  ...
}
渲染dicom图像
  • "<“img src=“imageURL” />”
  • "<“svg />”
  • "<“canvas />”
    使用canvas方式显示,既然知道pixel data, 只需将其值映射成屏幕像素值即可。
    由于pixel值的范围并不是屏幕像素0-255范围内,需要做相应的映射。modality lut, voi lut
  • modality lut, 像素存储值到实际输出值(OD值,CT值等)的映射,output = slope(0028, 1053) * store_value + intercept(0028, 1052)
  • voi lut ,映射函数由linear、linear_exact、sigmoid,其具体取值由voi lut function(0028, 1056)决定,缺省值为linear. voi lut 函数的参数是windowCenter(0028, 1050)和window width(0028, 1051).对于linear形式,窗宽窗位决定了一维直线上的一段区域,落在该区域的CT值(假定)将会被线性映射到0-255区间内,在其范围外的将被clamp
  • 像素值的映射有一定的顺序,先做modality lut, 在做voi lut
  const {
   pixels, rows, columns} = dicom;
  const canvas = initCanvas();
  const context = canvas.getContext('2d');
  // draw
  for (let i = 0; i < rows; i++) {
   
    for (let j = 0; j < coloumns; j++)  {
   
      const value = voiLutFunc(modalityLutFunc(pixels[i * columns + j]))
      context.save();
      context.fillStyle(value)
      context.fillRect(i, j, 1, 1);
      context.restore();
    }
  }

太低效
canvasContext2d.putImageData(imageData, dx, dy)
imageData 对象,表示一定矩形区域内的像素值。每个像数值由RGBA四分分量,每个分量的数据类型为Uint8ClampedArray(对于超出0-255区间内的值会被裁剪)。data属性为Uint8ClampedArray数组,像素值在数组中依次排列。
imageData对象,可以由CanvasRenderingContext2D.createImageData/getImageData创建。

//...
// 假设图像为灰度图
const imageData = context.createImageData(rows, columns);
const storedPixels = imageData.data;
let index = 0;
  for (let i = 0; i < rows; i++) {
   
    for (let j = 0; j < coloumns; j++)  {
   
      const grayValue = voiLutFunc(modalityLutFunc(pixels[i*columns + j]))
      storedPixels[index++] = grayValue

你可能感兴趣的:(前端,javascript)