python - 使用 numpy 高效地将 16 位图像数据转换为 8 位显示,具有强度缩放

标签 python image image-processing numpy

我经常将 16 位灰度图像数据转换为 8 位图像数据进行显示。调整最小和最大显示强度以突出图像的“有趣”部分几乎总是有用的。

下面的代码大致可以满足我的要求,但它丑陋且效率低下,并且会生成许多图像数据的中间副本。 如何以最少的内存占用和处理时间实现相同的结果?

import numpy

image_data = numpy.random.randint( #Realistic images would be much larger
    low=100, high=14000, size=(1, 5, 5)).astype(numpy.uint16)

display_min = 1000
display_max = 10000.0

print(image_data)
threshold_image = ((image_data.astype(float) - display_min) *
                   (image_data > display_min))
print(threshold_image)
scaled_image = (threshold_image * (255. / (display_max - display_min)))
scaled_image[scaled_image > 255] = 255
print(scaled_image)
display_this_image = scaled_image.astype(numpy.uint8)
print(display_this_image)

最佳答案

你正在做的是halftoning你的形象。

其他人提出的方法效果很好,但他们一遍又一遍地重复大量昂贵的计算。由于在 uint16 中最多有 65,536 个不同的值,因此使用查找表 (LUT) 可以大大简化事情。由于 LUT 很小,您不必担心就地做事或不创建 bool 数组。以下代码重用了 Bi Rico 的函数来创建 LUT:

import numpy as np
import timeit

rows, cols = 768, 1024
image = np.random.randint(100, 14000,
                             size=(1, rows, cols)).astype(np.uint16)
display_min = 1000
display_max = 10000

def display(image, display_min, display_max): # copied from Bi Rico
    # Here I set copy=True in order to ensure the original image is not
    # modified. If you don't mind modifying the original image, you can
    # set copy=False or skip this step.
    image = np.array(image, copy=True)
    image.clip(display_min, display_max, out=image)
    image -= display_min
    np.floor_divide(image, (display_max - display_min + 1) / 256,
                    out=image, casting='unsafe')
    return image.astype(np.uint8)

def lut_display(image, display_min, display_max) :
    lut = np.arange(2**16, dtype='uint16')
    lut = display(lut, display_min, display_max)
    return np.take(lut, image)


>>> np.all(display(image, display_min, display_max) ==
           lut_display(image, display_min, display_max))
True
>>> timeit.timeit('display(image, display_min, display_max)',
                  'from __main__ import display, image, display_min, display_max',
                   number=10)
0.304813282062
>>> timeit.timeit('lut_display(image, display_min, display_max)',
                  'from __main__ import lut_display, image, display_min, display_max',
                  number=10)
0.0591987428298

所以有 x5 的加速,这不是坏事,我想......

关于python - 使用 numpy 高效地将 16 位图像数据转换为 8 位显示,具有强度缩放,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14464449/

相关文章:

python - 如何确保字符串的格式正确

python - 使用 pandas python 将 2 个 groupby 输出与 lambda 结合起来

python - 聚合和填充缺失日期(天和小时)的数据

python - 为什么字符 ID 160 在 PDFMiner 中不被识别为 Unicode?

鼠标悬停时 CSS 悬停消失

python - 在不知道第二个坐标的情况下获取直线上的点/像素

image - MATLAB 图标题被截断

javascript - 通过其 src 获取图像的自然宽度

opencv - 减少opencv中模板匹配的误检

python - 使用 scikit-image 将 png 转换为 jpeg