转换后图像变暗
Image turns dark after converting
我正在处理包含 .mha 文件的数据集。我想将这些文件转换为 png/tiff 以进行某些工作。我正在使用 Medpy 库进行转换。
image_data, image_header = load('image_path/c0001.mha')
from medpy.io import save
save(image_data, 'image_save_path/new_image.png', image_header)
其实我可以把图片转换成png/tiff格式,但是转换后的图片变暗了。我附上下面的截图。如何成功转换图片?
您可以应用“对比度拉伸”。
image_data
的动态范围约为[0, 4095] - 最小值约为0,最大值约为4095(2^12-1)。
您正在将图像保存为 16 位 PNG。
当您显示 PNG 文件时,查看器假定最大值为 2^16-1(16 位的动态范围为 [0, 65535])。
查看器假设 0 是黑色,2^16-1 是白色,并且线性缩放之间的值。
在您的例子中,白色像素值约为 4095,因此它转换为 [0, 65535] 范围内的非常深的灰色。
最简单的解决方案是将 image_data
乘以 16
:
from medpy.io import load, save
image_data, image_header = load('image_path/c0001.mha')
save(image_data*16, 'image_save_path/new_image.png', image_header)
一个更复杂的解决方案是应用线性“对比度拉伸”。
我们可以将所有像素的低 1% 转换为 0,将像素的高 1% 转换为 2^16-1,然后线性缩放中间的像素。
import numpy as np
from medpy.io import load, save
image_data, image_header = load('image_path/c0001.mha')
tmp = image_data.copy()
tmp[tmp == 0] = np.median(tmp) # Ignore zero values by replacing them with median value (there are a lot of zeros in the margins).
tmp = tmp.astype(np.float32) # Convert to float32
# Get the value of lower and upper 1% of all pixels
lo_val, up_val = np.percentile(tmp, (1, 99)) # (for current sample: lo_val = 796, up_val = 3607)
# Linear stretching: Lower 1% goes to 0, upper 1% goes to 2^16-1, other values are scaled linearly
# Clipt to range [0, 2^16-1], round and convert to uint16
#
img = np.round(((tmp - lo_val)*(65535/(up_val - lo_val))).clip(0, 65535)).astype(np.uint16) # (for current sample: subtract 796 and scale by 23.31)
img[image_data == 0] = 0 # Restore the original zeros.
save(img, 'image_save_path/new_image.png', image_header)
上述方法增强了对比度,但丢失了一些原始信息。
如果你想要更高的对比度,你可以使用 non-linear 方法,提高可见性,但会失去一些“完整性”。
这是“线性拉伸”结果(缩小):
您的数据显然限于 12 位(白色为 2**12-1
,即 4095),而此上下文中的 PNG 图像为 16 位(白色为 2**16-1
,即 65535) .由于这个原因,您的 PNG 图像太暗,看起来几乎是黑色的(但如果您仔细观察,它不是)。
您可以应用的最精确的转换如下:
import numpy as np
from medpy.io import load, save
def convert_to_uint16(data, source_max):
target_max = 65535 # 2 ** 16 - 1
# build a linear lookup table (LUT) indexed from 0 to source_max
source_range = np.arange(source_max + 1)
lut = np.round(source_range * target_max / source_max).astype(np.uint16)
# apply it
return lut[data]
image_data, image_header = load('c0001.mha')
new_image_data = convert_to_uint16(image_data, 4095) # 2 ** 12 - 1
save(new_image_data, 'new_image.png', image_header)
输出:
N.B.: new_image_data = image_data * 16
对应convert_to_uint16
中的65535
替换为65520
(4095 * 16
)
我正在处理包含 .mha 文件的数据集。我想将这些文件转换为 png/tiff 以进行某些工作。我正在使用 Medpy 库进行转换。
image_data, image_header = load('image_path/c0001.mha')
from medpy.io import save
save(image_data, 'image_save_path/new_image.png', image_header)
其实我可以把图片转换成png/tiff格式,但是转换后的图片变暗了。我附上下面的截图。如何成功转换图片?
您可以应用“对比度拉伸”。
image_data
的动态范围约为[0, 4095] - 最小值约为0,最大值约为4095(2^12-1)。
您正在将图像保存为 16 位 PNG。
当您显示 PNG 文件时,查看器假定最大值为 2^16-1(16 位的动态范围为 [0, 65535])。
查看器假设 0 是黑色,2^16-1 是白色,并且线性缩放之间的值。
在您的例子中,白色像素值约为 4095,因此它转换为 [0, 65535] 范围内的非常深的灰色。
最简单的解决方案是将 image_data
乘以 16
:
from medpy.io import load, save
image_data, image_header = load('image_path/c0001.mha')
save(image_data*16, 'image_save_path/new_image.png', image_header)
一个更复杂的解决方案是应用线性“对比度拉伸”。
我们可以将所有像素的低 1% 转换为 0,将像素的高 1% 转换为 2^16-1,然后线性缩放中间的像素。
import numpy as np
from medpy.io import load, save
image_data, image_header = load('image_path/c0001.mha')
tmp = image_data.copy()
tmp[tmp == 0] = np.median(tmp) # Ignore zero values by replacing them with median value (there are a lot of zeros in the margins).
tmp = tmp.astype(np.float32) # Convert to float32
# Get the value of lower and upper 1% of all pixels
lo_val, up_val = np.percentile(tmp, (1, 99)) # (for current sample: lo_val = 796, up_val = 3607)
# Linear stretching: Lower 1% goes to 0, upper 1% goes to 2^16-1, other values are scaled linearly
# Clipt to range [0, 2^16-1], round and convert to uint16
#
img = np.round(((tmp - lo_val)*(65535/(up_val - lo_val))).clip(0, 65535)).astype(np.uint16) # (for current sample: subtract 796 and scale by 23.31)
img[image_data == 0] = 0 # Restore the original zeros.
save(img, 'image_save_path/new_image.png', image_header)
上述方法增强了对比度,但丢失了一些原始信息。
如果你想要更高的对比度,你可以使用 non-linear 方法,提高可见性,但会失去一些“完整性”。
这是“线性拉伸”结果(缩小):
您的数据显然限于 12 位(白色为 2**12-1
,即 4095),而此上下文中的 PNG 图像为 16 位(白色为 2**16-1
,即 65535) .由于这个原因,您的 PNG 图像太暗,看起来几乎是黑色的(但如果您仔细观察,它不是)。
您可以应用的最精确的转换如下:
import numpy as np
from medpy.io import load, save
def convert_to_uint16(data, source_max):
target_max = 65535 # 2 ** 16 - 1
# build a linear lookup table (LUT) indexed from 0 to source_max
source_range = np.arange(source_max + 1)
lut = np.round(source_range * target_max / source_max).astype(np.uint16)
# apply it
return lut[data]
image_data, image_header = load('c0001.mha')
new_image_data = convert_to_uint16(image_data, 4095) # 2 ** 12 - 1
save(new_image_data, 'new_image.png', image_header)
输出:
N.B.: new_image_data = image_data * 16
对应convert_to_uint16
65535
替换为65520
(4095 * 16
)