这里有两个问题:您的单色数据具有比 RGB 显示的更高的分辨率(例如值范围),因此您不能直接将像素数据映射到 RGB 数据。
值范围取决于Bits Stored
标签 - 对于 12 的典型值,数据范围将是 4096。最简单的实现可能只是缩小数字,在本例中为 16。
您的代码的第二个问题:要表示 RGB 中的单色值,您必须添加 3 个具有相同值的颜色分量:
let rgbaIdx = 0
let rgbIdx = 0
let pixelCount = 512 * 512
let scaleFactor = 16 // has to be calculated in real code
for ( let idx = 0; idx < pixelCount; idx++ ) {
# assume Little Endian
let pixelValue = pixelData[ rgbIdx ] + pixelData[ rgbIdx + 1 ] * 256
let displayValue = Math.round(pixelValue / scaleFactor)
imageData.data[ rgbaIdx ] = displayValue
imageData.data[ rgbaIdx + 1 ] = displayValue
imageData.data[ rgbaIdx + 2 ] = displayValue
imageData.data[ rgbaIdx + 3 ] = 255
rgbaIdx += 4
rgbIdx += 2
}
为了获得更好的表示,您必须考虑 VOI LUT 而不仅仅是缩小比例。如果您定义了Window Center
/Window Width
标签,您可以计算最小值和最大值并从该范围获取比例因子:
let minValue = windowCenter - windowWidth / 2
let maxValue = windowCenter + windowWidth / 2
let scaleFactor = (maxValue - minValue) / 256
...
let pixelValue = pixelData[ rgbIdx ] + pixelData[ rgbIdx + 1 ] * 256
let displayValue = max((pixelValue - minValue) / scaleFactor), 255)
...
编辑:正如@WilfRosenbaum 所观察到的:如果您没有VOI LUT(如WindowCenter 和WindowWidth 的空值所建议的那样),您最好自己计算一个。为此,您必须计算像素数据的最小值/最大值:
let minValue = 1 >> 16
let maxValue = 0
for ( let idx = 0; idx < pixelCount; idx++ ) {
let pixelValue = pixelData[ rgbIdx ] + pixelData[ rgbIdx + 1 ] * 256
minValue = min(minValue, pixelValue)
maxValue = max(maxValue, pixelValue)
}
let scaleFactor = (maxValue - minValue) / 256
然后使用与 VOI LUT 相同的代码。
几点注意事项:
- 如果您有模态 LUT,则必须在 VOI LUT 之前应用它;CT图像通常有一个(RescaleSlope/RescaleIntercept),虽然这个只有一个身份LUT,所以你可以忽略它
- 您可以有多个
WindowCenter
/WindowWindow
值对,或者可以有一个 VOI LUT 序列,这里也不考虑
- 代码不在我的脑海里,所以它可能有错误