图像数据类型及其含义¶
In skimage
, images are simply numpy arrays, which support a variety of
data types 1, i.e. "dtypes". To avoid distorting image intensities (see
Rescaling intensity values), we assume that images use the following dtype
ranges:
数据类型 |
射程 |
---|---|
uint8 |
0到255 |
Uint16 |
0至65535 |
Uint32 |
0到232 -1 |
浮动 |
-1到1或0到1 |
Int8 |
-128至127 |
Int16 |
-32768至32767 |
int32 |
-2f2f2 31 至231 -1 |
请注意,浮点图像应该限制在-1到1的范围内,即使数据类型本身可能超过这个范围;另一方面,所有整型数据类型的像素强度都可以跨越整个数据类型范围。除了几个例外, 64-bit (u)int images are not supported 。
中的函数 skimage
被设计成可以接受这些数据类型中的任何一种,但是为了提高效率, 可能返回不同数据类型的图像 (请参阅 Output types )。如果您需要特定的数据类型, skimage
提供用于转换数据类型和正确调整图像强度的实用程序函数(请参见 Input types )。你应该 切勿使用 astype
,因为它违反了以下关于数据类型范围的假设:
>>> from skimage.util import img_as_float
>>> image = np.arange(0, 50, 10, dtype=np.uint8)
>>> print(image.astype(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位单位。 |
img_as_uint |
转换为16位uint。 |
img_as_int |
转换为16位整型。 |
这些函数将图像转换为所需的数据类型并 适当地重新调整其值 ::
>>> from skimage.util import img_as_ubyte
>>> image = np.array([0, 0.5, 1], dtype=float)
>>> img_as_ubyte(image)
array([ 0, 128, 255], dtype=uint8)
注意!这些转换可能会导致精度损失,因为8位不能保存与64位相同的信息量::
>>> image = np.array([0, 0.5, 0.503, 1], dtype=float)
>>> image_as_ubyte(image)
array([ 0, 128, 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.util import img_as_uint
>>> out = img_as_uint(sobel(image))
>>> plt.imshow(out)
使用OpenCV¶
您可能需要使用使用 skimage
使用 OpenCV 或者反之亦然。OpenCV图像数据可以在NumPy中访问(无需复制)(因此,也可以在SCRICKIT-IMAGE中访问)。OpenCV对彩色图像使用BGR(而不是SCRKIT-IMAGE的RGB),默认情况下其dtype为uint8(参见 Image data types and what they mean )。BGR代表蓝、绿、红。
将BGR转换为RGB或反之亦然¶
中的彩色图像 skimage
OpenCV有3个维度:宽度、高度和颜色。RGB和BGR使用相同的颜色空间,只是颜色顺序相反。
请注意,在 scikit-image
我们通常指的是 rows
和 columns
而不是宽度和高度(请参见 坐标约定 )。
下面的指令有效地颠倒了颜色的顺序,使行和列不受影响。
>>> image = image[:, :, ::-1]
通过使用OpenCV中的图像 skimage
¶
如果CV_IMAGE是无符号字节的数组, skimage
默认情况下会理解它。如果您更喜欢使用浮点图像, img_as_float()
可用于转换图像::
>>> from skimage.util import img_as_float
>>> image = img_as_float(any_opencv_image)
使用来自 skimage
使用OpenCV¶
相反的情况可以通过以下方式实现 img_as_ubyte()
::
>>> from skimage.util import img_as_ubyte
>>> cv_image = img_as_ubyte(any_skimage_image)
图像处理流水线¶
此dtype行为允许您将任何 skimage
函数,而不用担心图像数据类型。另一方面,如果要使用需要特定数据类型的定制函数,则应该调用其中一个数据类型转换函数(在这里, func1
和 func2
是 skimage
函数):
>>> from skimage.util 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位深度存储图像。如果这些图像存储在具有dtype uint16的数组中,则图像不会扩展到整个亮度范围,因此会显得比应有的更暗。若要更正此错误,可以使用 rescale_intensity
函数来重新调整图像的比例,使其使用完整的数据类型范围::
>>> from skimage import exposure
>>> image = exposure.rescale_intensity(img10bit, in_range=(0, 2**10 - 1))
在这里, in_range
参数设置为10位图像的最大范围。默认情况下, rescale_intensity
扩展了 in_range
与数据类型的范围相匹配。 rescale_intensity
还接受字符串作为输入 in_range
和 out_range
,所以上面的例子也可以写成::
>>> image = exposure.rescale_intensity(img10bit, in_range='uint10')
关于负值的注记¶
人们经常用带符号的dtype表示图像,即使他们只操作图像的正值(例如,在int8图像中仅使用0-127)。因此,转换函数 只传播积极的价值观 在无符号数据类型的整个范围内的有符号数据类型。换句话说,当从有符号数据类型转换为无符号数据类型时,负值将被剪裁为0。(在带符号的数据类型之间转换时保留负值。)为了防止这种剪切行为,您应该事先重新调整图像的比例::
>>> image = exposure.rescale_intensity(img_int32, out_range=(0, 2**31 - 1))
>>> img_uint8 = img_as_ubyte(image)
这种行为是对称的:无符号数据类型中的值仅分布在有符号数据类型的正范围内。