重要
Databricks 建議您使用二進位檔案資料來源,將影像資料載入 Spark DataFrame 做為原始位元組。 如需處理影像資料的建議工作流程,請參閱影像應用程式的參考解決方案。
影像資料來源提供標準 API,將影像檔案以解碼結構形式載入 Spark DataFrames,讓你直接存取影像中繼資料,如高度、寬度、通道數及原始像素資料。 它主要用於機器學習預處理流程中,在除了像素資料之外還需要結構化影像欄位的情況下。 Azure Databricks 支援用於批次讀取的映像資料來源,包括針對已組織之映像目錄的資料分割探索。 若要讀取影像檔,請將資料來源 format 指定為 image。
先決條件
Azure Databricks 不需要額外設定即可使用映像資料來源。
選項
使用 .option().options() 和 DataFrameReader 方法來配置影像資料來源。 完整支援選項清單,請參閱 Spark API 選項參考。
Usage
以下範例示範如何使用 Spark DataFrame API 載入影像檔案、選取影像元資料欄位、顯示影像縮圖,以及將解碼影像資料儲存到 Delta 表格。
讀取影像檔案
使用 Apache Spark DataFrame 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 表格。
Note
影像資料來源儲存解碼後的像素資料,這使得磁碟使用量相較於原始位元組增加。 為了節省儲存空間的持久性,建議改用 二進位檔案 資料來源。
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>")
輸出結構描述
影像檔案會載入為 DataFrame,其中包含名為 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、彩色影像(例如 RGB)3 和帶有 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 時會解碼影像檔案,因此資料大小增加,並有以下限制:
- 持久化時的磁碟使用情況:解碼影像資料遠大於原始位元組。 如果你將 DataFrame 持久化為 Delta 表格,儲存原始位元組而非解碼資料以節省磁碟空間。
- 洗牌效能:洗牌解碼影像資料需要更多磁碟空間與網路頻寬,導致洗牌操作較慢。 在您的流程中,盡可能延後解碼。
- 固定解碼函式庫:影像資料來源使用 javax Image IO 函式庫來解碼影像,這會防止你使用其他解碼函式庫來提升效能或自訂解碼邏輯。
為避免這些限制,請使用二進位檔案資料來源載入影像資料,並僅在必要時解碼。
其他資源
- 讀取二進位檔案:如果你的工作負載需要原始影像位元組而非解碼結構,二進位檔案資料來源可避免解碼的負擔與影像資料來源的限制。