将Dicom图像渲染到canvas时出现画面过亮问题如何解决
DICOM图像Canvas渲染过亮问题修复方案
问题根因
- 未应用重缩放转换:DICOM存储的原始像素值不能直接用于窗宽窗位计算,需要先通过
RescaleSlope(重缩放斜率)和RescaleIntercept(重缩放截距)转换为实际像素值,缺失这一步会导致像素值计算偏差 - 像素符号处理错误:如果DICOM的
PixelRepresentation标签值为1,代表存储的是有符号16位整数,当前代码按无符号规则拼接会得到远高于实际的数值,直接导致画面过亮 - 字节序未适配:没有根据DICOM传输语法判断大小端拼接逻辑,默认的小端拼接规则遇到大端存储的DICOM文件时,读取的像素值完全错误
- 显示值钳制不全:仅对显示值做了上限255的限制,未处理小于0的情况,逻辑存在漏洞
修正后代码
public redraw() { // 提前从DICOM标签中读取以下必要参数 const rescaleSlope = dicomTags.RescaleSlope || 1 const rescaleIntercept = dicomTags.RescaleIntercept || 0 const isSigned = dicomTags.PixelRepresentation === 1 const isLittleEndian = dicomTags.TransferSyntaxUID.includes('LittleEndian') const buffer8 = this.base64ToArrayBuffer(entry) let minValue = (windowCenter - windowWidth) / 2; let maxValue = (windowCenter + windowWidth) / 2; let scale = (maxValue - minValue) / 256; for (let i = 0, j = 0; i < dstBmp.length; i += 4, j += 2) { let pixelValue // 按大小端规则拼接16位像素值 if (isLittleEndian) { pixelValue = buffer8[j] + (buffer8[j + 1] << 8) } else { pixelValue = (buffer8[j] << 8) + buffer8[j + 1] } // 处理有符号16位值 if (isSigned && pixelValue > 0x7FFF) { pixelValue = pixelValue - 0x10000 } // 应用重缩放转换得到实际像素值 pixelValue = pixelValue * rescaleSlope + rescaleIntercept // 计算显示值并同时做上下限钳制 let displayValue = Math.min(Math.max((pixelValue - minValue) / scale, 0), 255) dstBmp[i + 0] = displayValue dstBmp[i + 1] = displayValue dstBmp[i + 2] = displayValue dstBmp[i + 3] = 255 } const idata = new ImageData(dstBmp, entryWidth, entryHeight); context.putImageData(idata, 0, 0); } public base64ToArrayBuffer(base64: string) { const binary_string = window.atob(base64); const len = binary_string.length; const bytes = new Uint8Array(len); for (let i = 0; i < len; i++) { bytes[i] = binary_string.charCodeAt(i); } return bytes; }
内容的提问来源于stack exchange,提问作者ffsa
相关产品推荐
相关产品推荐

