重要
Databricks 建议使用二进制文件数据源将图像数据以原始字节形式加载到 Spark 数据帧中。 如需了解建议的用于处理图像数据的工作流,请参阅图像应用程序的参考解决方案。
图像数据源提供一个标准 API,用于将图像文件作为解码结构加载到 Spark 数据帧中,从而直接访问图像元数据,例如高度、宽度、通道计数和原始像素数据。 它主要用于机器学习预处理管道,其中结构化图像字段与像素数据一起是必需的。 Azure Databricks支持用于批量读取的图像数据源,包括已组织的映像目录的分区发现。 若要读取图像文件,请将数据源 format 指定为 image。
先决条件
Azure Databricks不需要其他配置即可使用映像数据源。
选项
使用DataFrameReader的.option()和.options()方法来配置图像数据源。 有关支持选项的完整列表,请参阅 Spark API 选项参考。
Usage
以下示例演示如何使用 Spark 数据帧 API 加载图像文件、选择图像元数据字段、显示图像缩略图以及将解码的图像数据保存到 Delta 表。
读取图像文件
使用 Apache Spark 数据帧 API 将图像文件加载到 DataFrame 中。 您可以通过提供目录路径来导入嵌套的目录结构,并通过指定包含分区目录的路径(例如 /path/to/dir/date=2018-01-02/category=automobile)来使用分区发现功能。
Python
# Read all images from a directory
df = spark.read.format("image").load("/Volumes/<catalog>/<schema>/<volume>/images/")
display(df)
# Use partition discovery by specifying a partitioned path
df = spark.read.format("image").load("/Volumes/<catalog>/<schema>/<volume>/images/date=2024-01-01/category=dogs/")
display(df)
Scala
// Read all images from a directory
val df = spark.read.format("image").load("/Volumes/<catalog>/<schema>/<volume>/images/")
df.show()
// Use partition discovery by specifying a partitioned path
val partitioned = spark.read.format("image").load("/Volumes/<catalog>/<schema>/<volume>/images/date=2024-01-01/category=dogs/")
partitioned.show()
SQL
-- Read all images from a directory
SELECT * FROM read_files(
'/Volumes/<catalog>/<schema>/<volume>/images/',
format => 'image'
)
选择图像元数据
若要在不处理完整像素数据的情况下使用图像维度或通道信息,请从 image 结构列中选择特定字段。
Python
df = spark.read.format("image").load("/Volumes/<catalog>/<schema>/<volume>/images/")
metadata = df.select("image.origin", "image.height", "image.width", "image.nChannels")
display(metadata)
Scala
val df = spark.read.format("image").load("/Volumes/<catalog>/<schema>/<volume>/images/")
val metadata = df.select("image.origin", "image.height", "image.width", "image.nChannels")
metadata.show()
SQL
SELECT image.origin, image.height, image.width, image.nChannels FROM read_files(
'/Volumes/<catalog>/<schema>/<volume>/images/',
format => 'image'
)
显示图像数据
使用图像数据源时,Databricks display 函数直接在 image 列中呈现图像缩略图。 有关支持的显示选项,请参阅 “图像 ”。
Python
df = spark.read.format("image").load("/Volumes/<catalog>/<schema>/<volume>/images/")
display(df)
Scala
val df = spark.read.format("image").load("/Volumes/<catalog>/<schema>/<volume>/images/")
df.show()
SQL
SELECT * FROM read_files(
'/Volumes/<catalog>/<schema>/<volume>/images/',
format => 'image'
)
将图像数据保存到 Delta 表
若要在将图像数据加载回时提高读取性能,请将 DataFrame 保存到 Delta 表。
注释
图像数据源存储解码的像素数据,这比原始字节增加了磁盘使用量。 对于存储高效的持久性,请改用 二进制文件 数据源。
Python
df = spark.read.format("image").load("/Volumes/<catalog>/<schema>/<volume>/images/")
df.write.format("delta").saveAsTable("<catalog>.<schema>.<table>")
Scala
val df = spark.read.format("image").load("/Volumes/<catalog>/<schema>/<volume>/images/")
df.write.format("delta").saveAsTable("<catalog>.<schema>.<table>")
输出架构
图像文件作为数据帧加载,数据帧包含一个名为image的单个结构类型的列,其中包含以下字段:
root
|-- image: struct (nullable = true)
| |-- origin: string (nullable = true)
| |-- height: integer (nullable = false)
| |-- width: integer (nullable = false)
| |-- nChannels: integer (nullable = false)
| |-- mode: integer (nullable = false)
| |-- data: binary (nullable = false)
以下字段描述图像文件及其解码的像素数据。
-
origin:源映像的文件路径。 -
height:图像的高度(以像素为单位)。 -
width:图像的宽度(以像素为单位)。 -
nChannels:颜色通道数。 对于灰度图像,典型值为 1,彩色图像为 3(例如 RGB),对于带 alpha 通道的彩色图像,为 4。 -
mode:一个整数标志,指示如何解释数据字段。 它指定数据类型和存储数据的通道顺序。 字段的值应(但不强制执行)映射到下表中显示的 OpenCV 类型之一。 OpenCV 类型为 1、2、3 或 4 通道定义,为像素值定义多个数据类型。 通道顺序指定了颜色存储的顺序。 例如,如果你有一个具有红色、蓝色和绿色成分的典型三通道图像,则有六种可能的排序。 大多数库使用 RGB 或 BGR。 三(四)通道 OpenCV 类型应采用 BGR(A) 顺序。
在 OpenCV 中将类型映射到数字(数据类型 x 通道数)
| 类型 | C1 | C2 | C3 | C4 |
|---|---|---|---|---|
| CV_8U | 0 | 8 | 16 | 24 |
| CV_8S | 1 | 9 | 17 | 25 |
| CV_16U | 2 | 10 | 18 | 26 |
| CV_16S | 3 | 11 | 19 | 27 |
| CV_32U | 4 | 12 | 20 | 28 |
| CV_32S | 5 | 13 | 21 | 29 |
| CV_64F | 6 | 14 | 22 | 30 |
-
data:以二进制格式存储的图像数据。 图像数据表示为三维数组,其维度形状(高度、宽度、nChannels)和模式字段指定的数组值类型为 t。 数组以行优先顺序存储。
Limitations
由于图像数据源在数据帧创建过程中解码图像文件,因此会增大数据大小,并具有以下限制:
- 保留时磁盘使用情况:解码的图像数据明显大于原始字节。 如果将 DataFrame 保存到 Delta 表,则存储原始字节而不是解码的数据以节省磁盘空间。
- 混洗性能:对已解码的图像数据进行混洗需要更多的磁盘空间和网络带宽,因此会导致混洗操作变慢。 在管道中尽可能延迟解码。
- 修复了解码库:图像数据源使用 javax 图像 IO 库解码图像,这可以防止使用替代解码库来提高性能或自定义解码逻辑。
若要避免这些限制,请使用二进制文件数据源加载图像数据,并根据需要进行解码。
其他资源
- 读取二进制文件:如果工作负荷需要原始映像字节而不是解码的结构,则二进制文件数据源可避免图像数据源的解码开销和限制。