本文介绍了使用numpy有效地将16位图像数据转换为8位用于显示,具有强度缩放的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I frequently convert 16-bit grayscale image data to 8-bit image data for display. It's almost always useful to adjust the minimum and maximum display intensity to highlight the 'interesting' parts of the image.

下面的代码粗略地做了我想要的,但它很难看效率低下,并制作图像数据的许多中间副本。 如何以最小的内存占用和处理时间实现相同的结果?

The code below does roughly what I want, but it's ugly and inefficient, and makes many intermediate copies of the image data. How can I achieve the same result with a minimum memory footprint and processing time?

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)


推荐答案

你在做什么是你的形象。

What you are doing is halftoning your image.

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

The methods proposed by others work great, but they are repeating a lot of expensive computations over and over again. Since in a uint16 there are at most 65,536 different values, using a look-up table (LUT) can streamline things a lot. And since the LUT is small, you don't have to worry that much about doing things in place, or not creating boolean arrays. The following code reuses Bi Rico's function to create the 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加速,这不是一件坏事,我想......

So there is a x5 speed-up, which is not a bad thing, I guess...

这篇关于使用numpy有效地将16位图像数据转换为8位用于显示,具有强度缩放的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-29 10:15