Image data types and what they mean
图像数据类型及其含义
在skimage
,图像是简单的numpy数组,支持各种数据类型[1],即
“dtypes”。为了避免扭曲图像强度(请参阅调整强度值),我们假设图像使用以下dtype范围:
数据类型 | 范围 |
---|---|
UINT8 | 0到255 |
UINT16 | 0至65535 |
UINT32 | 0至232 |
浮动 | -1到1或0到1 |
INT8 | -128至127 |
INT16 | -32768至32767 |
INT32 | -231至231-1 |
请注意,即使数据类型本身可能超过此范围,浮动图像也应限制在-1到1的范围内; 另一方面,所有的整型数据都具有可以跨越整个数据类型范围的像素强度。除少数例外,不支持64位(u)int图像
。
函数skimage
的设计使它们可以接受任何这些dtype,但为了提高效率,可能会返回不同
dtype 的图像
(请参见输出类型)。如果您需要特定的dtype,则skimage
提供实用程序函数,用于转换dtypes并适当重新调整图像强度(请参阅输入类型)。你不应该在图像上使用
astype
,因为它违反了有关dtype范围的这些假设:
>>> from skimage import img_as_float
>>> image = np.arange(0, 50, 10, dtype=np.uint8)
>>> print(image.astype(np.float)) # These float values are out of range.
[ 0. 10. 20. 30. 40.]
>>> print(img_as_float(image))
[ 0. 0.03921569 0.07843137 0.11764706 0.15686275]
输入类型
虽然我们旨在保留输入图像的数据范围和类型,但函数可能仅支持这些数据类型的一个子集。在这种情况下,输入将被转换为所需的类型(如果可能的话),并且如果需要存储器副本,则会向日志打印警告消息。类型要求应在文档中注明。
主包中的以下实用程序功能可供开发人员和用户使用:
函数名称 | 描述 |
---|---|
img_as_float | 转换为64位浮点。 |
img_as_ubyte | 转换为8位uint。 |
img_as_uint | 转换为16位uint。 |
img_as_int | 转换为16位整数。 |
这些功能将图像转换为所需的dtype并正确重新调整其值
。如果转换降低图像的精度,则会发出警告:
>>> from skimage import img_as_ubyte
>>> image = np.array([0, 0.5, 1], dtype=float)
>>> img_as_ubyte(image)
WARNING:dtype_converter:Possible precision loss when converting from
float64 to uint8
array([ 0, 128, 255], dtype=uint8)
使用上下文管理器可以在本地忽略警告:
>>> import warnings
>>> image = np.array([0, 0.5, 1], dtype=float)
>>> with warnings.catch_warnings():
... warnings.simplefilter("ignore")
... img_as_ubyte(image)
array([ 0, 128, 255], dtype=uint8)
此外,某些函数preserve_range
在范围转换方便但不必要的地方使用参数。例如,插入transform.warp
需要float类型的图像,其范围应该为0,1。因此,默认情况下,输入图像将重新缩放到此范围。但是,在某些情况下,图像值代表用户不希望重新缩放的物理测量结果,例如温度或降雨量值。与preserve_range=True
,数据的原始范围将被保留,即使输出是浮动图像。然后用户必须确保这个非标准图像被下游功能正确处理,这可能期望0,1的图像。
>>> from skimage import data
>>> from skimage.transform import rescale
>>> image = data.coins()
>>> image.dtype, image.min(), image.max(), image.shape
(dtype('uint8'), 1, 252, (303, 384))
>>> rescaled = rescale(image, 0.5)
>>> (rescaled.dtype, np.round(rescaled.min(), 4),
... np.round(rescaled.max(), 4), rescaled.shape)
(dtype('float64'), 0.0147, 0.9456, (152, 192))
>>> rescaled = rescale(image, 0.5, preserve_range=True)
>>> (rescaled.dtype, np.round(rescaled.min()),
... np.round(rescaled.max()), rescaled.shape
(dtype('float64'), 4.0, 241.0, (152, 192))
输出类型
函数的输出类型由函数作者确定,并且为了用户的利益进行记录。虽然这要求用户明确地将输出转换为需要的格式,但它确保不会发生不必要的数据副本。
需要特定类型输出(例如,用于显示目的)的用户可以写出:
>>> from skimage import img_as_uint
>>> out = img_as_uint(sobel(image))
>>> plt.imshow(out)
使用OpenCV
您可能需要使用使用OpenCV创建的图像skimage
,反之亦然。OpenCV图像数据可以在NumPy中(并且因此在scikit-image中)被访问(不复制)。OpenCV对彩色图像使用BGR(而不是scikit-image的RGB),默认情况下它的dtype为uint8(请参阅图像数据类型及其含义)。BGR代表蓝绿红。
将BGR转换为RGB,反之亦然
skimage
OpenCV中的彩色图像有三个维度:宽度,高度和颜色。RGB和BGR使用相同的颜色空间,但颜色顺序相反。
请注意,scikit-image
我们通常引用宽度和高度rows
,columns
而不是宽度和高度(请参阅坐标约定)。
以下指令有效地反转颜色的顺序,使行和列不受影响。
>>> image = image[:, :, ::-1]
使用来自OpenCV的图像 skimage
如果cv_image是一个无符号字节数组,skimage
默认情况下会理解它。如果你喜欢使用浮点图像,img_as_float()
可以用来转换图像:
>>> from skimage import img_as_float
>>> image = img_as_float(any_opencv_image)
使用skimageOpenCV中的图像
反过来可以通过以下方式实现img_as_ubyte()
:
>>> from skimage import img_as_ubyte
>>> cv_image = img_as_ubyte(any_skimage_image)
图像处理管道
这种dtype行为允许你将任何skimage
函数串起来,而不必担心图像dtype。在另一方面,如果你想使用需要特定的D型自定义函数,你应该叫的D型转换函数(在这里,func1
并func2
在skimage
功能):
>>> from skimage import img_as_float
>>> image = img_as_float(func1(func2(image)))
>>> processed_image = custom_func(image)
更好的是,您可以在内部转换图像并使用简化的处理管道:
>>> def custom_func(image):
... image = img_as_float(image)
... # do something
...
>>> processed_image = custom_func(func1(func2(image)))
重新调整强度值
在可能的情况下,函数应该避免盲目地拉伸图像强度(例如,重新缩放浮动图像以使最小和最大强度为0和1),因为这会严重扭曲图像。例如,如果您在黑暗的图像中寻找明亮的标记,则可能存在没有标记存在的图像; 扩展其输入强度以跨越整个范围会使背景噪声看起来像标记。
然而,有时候,你的图像应该跨越整个强度范围,但是没有。例如,某些相机可以存储每像素10,12或14位深度的图像。如果这些图像以dint uint16的形式存储在一个数组中,则图像不会在整个强度范围内延伸,因此会显得比它应该更暗淡。要更正此问题,可以使用该rescale_intensity
功能重新缩放图像,以便使用完整的dtype范围:
>>> from skimage import exposure
>>> image = exposure.rescale_intensity(img10bit, in_range=(0, 2**10 - 1))
这里,in_range
参数被设置为10位图像的最大范围。默认情况下,rescale_intensity
拉伸值in_range
以匹配dtype的范围。rescale_intensity
还接受字符串作为输入in_range
和out_range
,所以上面的例子也可以被写为:
>>> image = exposure.rescale_intensity(img10bit, in_range='uint10')
请注意负值
人们经常使用带符号的dtypes表示图像,尽管它们只是操纵图像的正值
(例如,在int8图像中仅使用0-127)。出于这个原因,转换函数仅在
无符号dtype的整个范围上传播带
符号dtype 的正值
。换句话说,从signed变换为unsigned dtypes时,负值将被剪切为0。(在带符号的dtypes之间转换时保留负值。)要防止此剪切行为,应该事先重新调整图像的缩放比例:
>>> image = exposure.rescale_intensity(img_int32, out_range=(0, 2**31 - 1))
>>> img_uint8 = img_as_ubyte(image)
此行为是对称的:无符号dtype中的值分布在签名dtype的正范围上。
参考
1 | http://docs.scipy.org/doc/numpy/user/basics.types.html |
---|