TensorFlow Hub 提供預訓練的 SSD 模型,簡化了物體偵測應用的開發流程。透過簡單的 API 呼叫即可載入模型,並使用 OpenCV 等工具進行影像預處理,將影像調整至模型輸入尺寸。接著,使用模型進行推理,取得邊界框、類別和置信度等資訊。為了視覺化結果,我們使用隨機顏色繪製邊界框,並標示對應的類別和置信度。同時,我們也比較了根據 MobileNets 和 ResNet 的 SSD 模型在推理時間上的差異,發現 ResNet 模型的推理時間略長,但準確性更高。除了 SSD,R-CNN 作為另一種主流物體偵測框架,採用兩階段的處理流程,包含區域提議、特徵提取和邊界框迴歸,以實作更精確的物體定位和分類別。

SSD模型的優點

SSD模型具有以下優點:

  • 實作實時物體偵測
  • 能夠處理不同大小的物體
  • 效率高,適合佈署在資源有限的裝置上

使用SSD模型

TensorFlow Hub提供了一系列預訓練的物體偵測模型,包括SSD模型。這些模型可以輕鬆地整合到物體偵測應用中,無需從頭開始訓練模型。

TensorFlow Hub是一個由Google開發的函式庫和平臺,提供了一系列預訓練的模型,包括物體偵測模型。這些模型可以用於各種任務,例如物體偵測、影像分類別等。

使用TensorFlow Hub的預訓練模型

要使用TensorFlow Hub的預訓練模型,需要先安裝TensorFlow Hub函式庫。然後,可以使用以下程式碼匯入必要的函式庫:

import numpy as np
import cv2
import tensorflow as tf
import tensorflow_hub as hub

載入預訓練模型

可以使用以下程式碼載入預訓練模型:

model = hub.load("https://tfhub.dev/tensorflow/ssd_mobilenet/v2/2")

載入影像

可以使用OpenCV函式庫載入影像:

img = cv2.imread("horse.jpg")

預處理影像

需要預處理影像以進行推理:

img = cv2.resize(img, (640, 640))
img = img / 255.0

進行推理

可以使用以下程式碼進行推理:

outputs = model(img)

處理輸出

需要處理輸出以取得最終的物體偵測結果:

boxes = outputs["detection_boxes"]
scores = outputs["detection_scores"]
classes = outputs["detection_classes"]

圖表翻譯:

  graph LR
    A[影像] --> B[預處理]
    B --> C[推理]
    C --> D[輸出]
    D --> E[處理輸出]
    E --> F[最終結果]

這個流程圖展示瞭如何使用SSD模型和TensorFlow Hub進行物體偵測。首先,需要載入影像和預訓練模型。然後,需要預處理影像以進行推理。接下來,需要進行推理以取得輸出。最後,需要處理輸出以取得最終的物體偵測結果。

OpenCV 影像處理入門

OpenCV 是一套開源的電腦視覺和機器學習函式庫,最初由 Intel 公司開發,現在由 OpenCV 社群維護。它支援多種程式語言,包括 C++、Python 等。OpenCV 提供了許多功能和演算法,用於影像和視訊處理、物體偵測和識別、以及機器學習。

影像讀取和顯示

要讀取影像,可以使用 cv2.imread() 函式,傳回一個 NumPy 陣列。然後,可以使用 cv2_imshow() 函式顯示影像。

import cv2

# 讀取影像
img = cv2.imread("horse.jpg")

# 調整影像大小
img = cv2.resize(img, dsize=(640, 640))

# 顯示影像
cv2_imshow(img)

影像大小和形狀

可以使用 img.shape 屬性來檢查影像的大小和形狀。例如:

print(img.shape)

這將傳回一個 tuple,包含影像的高度、寬度和通道數。

物體偵測模型

要使用預訓練的 SSD Mobilenet V1 物體偵測模型,需要先將影像大小調整為 640x640。然後,可以使用 np.expand_dims() 函式將影像轉換為 (1, 640, 640, 3) 的形狀。

import numpy as np

# 調整影像大小
img = np.expand_dims(img, 0)

# 檢查影像形狀
print(img.shape)

定義物體偵測模型

可以使用 TensorFlow Hub 的 hub API 將預訓練的模型包裝為 Keras 層。例如:

import tensorflow_hub as hub

# 定義模型 URL
model_url = "https://tfhub.dev/tensorflow/ssd_mobilenet_v1/fpn_640x640/1"

# 載入模型
model = hub.KerasLayer(model_url)

圖表翻譯:

  graph LR
    A[影像讀取] --> B[影像大小調整]
    B --> C[影像顯示]
    C --> D[物體偵測模型]
    D --> E[模型定義]
    E --> F[模型訓練]

內容解密:

上述程式碼示範瞭如何使用 OpenCV 讀取和顯示影像,調整影像大小,使用預訓練的 SSD Mobilenet V1 物體偵測模型,和定義模型。這些步驟是電腦視覺和機器學習中常用的技術。

物體偵測模型的建立和預測

載入預先訓練好的模型

為了建立物體偵測模型,我們需要載入一個預先訓練好的模型。這個模型可以從TensorFlow Hub中取得。首先,我們需要取得模型的URL。

hub_url = "https://tfhub.dev/tensorflow/ssd_mobilenet/v2/2"

接下來,我們可以使用TensorFlow Hub的KerasLayer來載入這個模型。

object_detector = hub.KerasLayer(hub_url)

建立模型

現在,我們可以使用這個載入的模型來建立我們自己的物體偵測模型。為了簡化這個過程,我們可以定義一個函式create_model()來建立模型。

def create_model():
    img_input = tf.keras.Input(shape=(None, None, 3), dtype=tf.uint8)
    outputs = object_detector(img_input)
    model = tf.keras.Model(inputs=img_input, outputs=outputs)
    return model

model = create_model()

預測物體

有了模型之後,我們就可以使用它來預測圖片中的物體。首先,我們需要準備好圖片的輸入資料。

detector_output = model.predict(img)

預測的結果是一個字典,包含了多個關鍵的訊息。

預測結果的解釋

預測結果的字典包含了以下幾個關鍵的訊息:

  • detection_multiclass_scores: 包含了每個檢測框的類別分數分佈。
  • raw_detection_scores: 包含了每個原始檢測框的類別分數對數。
  • detection_classes: 包含了每個檢測框的類別索引。
  • detection_scores: 包含了每個檢測框的分數。
  • detection_boxes: 包含了每個檢測框的座標。
  • raw_detection_boxes: 包含了未經過非最大值抑制的檢測框座標。
  • detection_anchor_indices: 包含了每個檢測框的錨點索引。
  • num_detections: 包含了檢測到的物體數量。

載入標籤檔

為了得到每個類別的名稱,我們需要載入標籤檔。這個檔案包含了Microsoft COCO 2017資料集的91個類別的詳細訊息。

!wget -qq https://raw.githubusercontent.com/tensorflow/models/master/research/object_detection/data/mscoco_complete_label_map.pbtxt

這個檔案可以幫助我們將類別索引對映到實際的類別名稱上。接下來,我們可以使用這個檔案來解釋預測結果,例如取得每個檢測框的類別名稱和分數等訊息。

下載標籤對應檔案並提取顯示名稱

首先,我們需要下載COCO 2017資料集的標籤對應檔案。這個檔案是一種文字檔,包含了資料集中的類別名稱。下載完成後,我們可以檢視檔案的內容。

!wget https://raw.githubusercontent.com/opencv/opencv/master/samples/dnn/models/coco_labels.txt

接下來,我們可以看到檔案的內容,如下圖所示:

標籤對應檔案內容

這個檔案包含了COCO 2017資料集的類別名稱。然而,我們只需要提取display_name的值。因此,我們可以建立一個函式叫做get_labels(),用於讀取這個檔案並提取display_name的值。

def get_labels(file):
    labels = []
    with open(file, "r") as file:
        for line in file:
            if "display_name" in line:
                # 提取display_name的值
                label = line.split(":")[1].strip().strip('"')
                labels.append(label)
    return labels

提取顯示名稱

現在,我們可以使用get_labels()函式來提取display_name的值。這個函式會讀取檔案,找到包含display_name的行,然後提取其值。

  flowchart TD
    A[讀取檔案] --> B[找到display_name]
    B --> C[提取display_name的值]
    C --> D[傳回顯示名稱]

圖表翻譯

上面的流程圖描述了get_labels()函式的執行流程。首先,函式會讀取檔案,然後找到包含display_name的行。接下來,函式會提取display_name的值,並傳回顯示名稱。

內容解密

get_labels()函式的實作相對簡單。首先,我們開啟檔案,然後逐行讀取檔案的內容。如果某一行包含display_name,我們就提取其值,並增加到labels列表中。最後,函式會傳回labels列表。這個列表包含了所有的顯示名稱。

物體偵測中的標籤和顏色生成

在進行物體偵測時,瞭解如何讀取和處理標籤檔案至關重要。標籤檔案包含了物體類別的資訊,例如 COCO 2017 資料集中的 91 個類別。下面我們將探討如何讀取這些標籤並為每個類別生成不同的顏色,以便於視覺化。

讀取標籤檔案

首先,我們需要讀取標籤檔案並提取出類別名稱。這可以透過以下步驟實作:

  1. 開啟標籤檔案(例如 “mscoco_complete_label_map.pbtxt”)。
  2. 逐行讀取檔案,檢查每行是否包含 “display_name” 字串。
  3. 如果找到,則使用引號("」)作為分隔符分割該行,提取出類別名稱。
  4. 將提取出的類別名稱增加到一個列表中(例如 labels)。

以下是實作這一步的示例程式碼:

import numpy as np

def get_labels(label_file):
    labels = []
    with open(label_file, 'r') as f:
        for line in f:
            if 'display_name' in line:
                label = line.split('"')[1]
                labels.append(label)
    return labels

LABELS = get_labels("mscoco_complete_label_map.pbtxt")

生成類別顏色

為了更好地視覺化,為每個類別生成不同的顏色是有益的。這可以透過以下步驟實作:

  1. 使用 numpy 生成一個隨機的 RGB 顏色列表,列表長度等於類別數量(在這裡是 91)。
  2. 每個 RGB 顏色由三個整陣列成,代表紅、綠、藍的強度,範圍從 0 到 255。

以下是實作這一步的示例程式碼:

BB_COLORS = np.random.randint(0, 255, size=(len(LABELS), 3))

這樣,每個類別就會有一個唯一的顏色,方便在視覺化中區分不同的物體類別。

結合使用

最終,LABELS 列表包含了所有類別的名稱,而 BB_COLORS 列表包含了每個類別對應的顏色。這些資訊可以用來繪製檢測到的邊界盒,並根據類別使用不同的顏色,從而提高視覺化的清晰度和可讀性。

內容解密:

  • get_labels 函式的作用是從指定的標籤檔案中讀取類別名稱,並傳回一個包含所有類別名稱的列表。
  • np.random.randint 函式用於生成隨機的 RGB 顏色列表,每個顏色對應一個類別。
  • LABELSBB_COLORS 列表之間的索引對應關係,使得每個類別都有一個唯一的顏色。

圖表翻譯:

  flowchart TD
    A[讀取標籤檔案] --> B[提取類別名稱]
    B --> C[生成RGB顏色列表]
    C --> D[傳回類別列表和顏色列表]
    D --> E[視覺化邊界盒]
    E --> F[展示結果]

這個流程圖描述了從讀取標籤檔案到視覺化邊界盒的整個過程,展示瞭如何將類別名稱和顏色列表結合使用,以實作不同類別的邊界盒使用不同的顏色。

物體偵測中的邊界框繪製

在物體偵測任務中,為了清晰地展示模型預測結果,通常會在輸入影像上繪製邊界框,以標記出被偵測到的物體。這些邊界框的顏色可以隨機生成,以區分不同的物體。

隨機顏色生成

RGB 值可以在 0 到 255 的範圍內隨機生成,以建立多種不同的顏色。這些隨機生成的顏色可以用於視覺化地區分和標記與不同物體相關的邊界框。

邊界框繪製函式

現在,我們可以撰寫一個名為 draw_bounding_boxes() 的函式,該函式讀取模型的預測輸出,並在輸入影像上繪製邊界框。以下是相關的程式碼:

def draw_bounding_boxes(img, output, colors, labels):
    bounding_boxes = output["detection_boxes"][0].shape[0]
    (H, W) = img.shape[1], img.shape[2]

    for i in range(bounding_boxes):
        confidence = output["detection_scores"][0][i]

        if confidence > 0.5:
            ymin, xmin, ymax, xmax = output["detection_boxes"][0][i]
            # 繪製邊界框的程式碼

在這個函式中,我們首先從模型的預測輸出中取得邊界框的數量和影像的尺寸。然後,我們遍歷每個邊界框,檢查其信心度是否大於 0.5。如果是,我們就提取邊界框的座標,並繪製它在影像上。

內容解密:

這個函式的主要目的是將模型的預測結果視覺化地呈現在輸入影像上。透過繪製邊界框,我們可以清晰地看到被偵測到的物體的位置和大小。這個函式的輸入包括輸入影像、模型的預測輸出、隨機生成的顏色和物體的標籤。函式的輸出是繪製了邊界框的影像。

圖表翻譯:

以下是邊界框繪製過程的視覺化圖表:

  flowchart TD
    A[輸入影像] --> B[模型預測]
    B --> C[邊界框繪製]
    C --> D[輸出影像]
    D --> E[視覺化結果]

這個圖表展示了從輸入影像到視覺化結果的整個過程。首先,模型對輸入影像進行預測,然後根據預測結果繪製邊界框,最後輸出繪製了邊界框的影像。

物體偵測模型的實作與最佳化

在上述程式碼中,定義了一個名為 draw_bounding_boxes 的函式,該函式用於繪製物體偵測模型的輸出結果。這個函式需要四個輸入引數:輸入影像、物體偵測模型的輸出、不同物體類別對應的 RGB 顏色值列表以及物體類別的標籤列表。

物體偵測模型的輸出處理

  1. 取得邊界框的數量:從物體偵測模型的輸出中取得邊界框的數量,根據 detection_boxes 的第一維度的形狀。
  2. 提取影像的高度和寬度:取得輸入影像的高度 (H) 和寬度 (W)。
  3. 迭代每個邊界框:對每個邊界框,提取其信心度分數。如果信心度分數超過某個閾值(在這裡是 0.5),則考慮這個邊界框。
  4. 提取邊界框的座標:從 detection_boxes 中提取邊界框的座標,並根據影像的尺寸進行縮放。
  5. 取得類別 ID 和對應的顏色:根據邊界框的類別 ID,從 colors 列表中取得對應的顏色值。

繪製邊界框和文字標籤

  1. 繪製邊界框:使用 OpenCV 的 rectangle 函式繪製邊界框,根據影像的尺寸和對應的顏色。
  2. 建立文字標籤:根據物體類別的標籤和信心度分數,建立一個文字標籤,格式為「類別標籤:信心度分數(小數點後四位)」。
  3. 增加文字標籤:使用 OpenCV 的 putText 函式增加文字標籤到影像上,位置在邊界框的左上角附近。

顯示結果

最後,呼叫 draw_bounding_boxes 函式並顯示結果。可以使用 cv2_imshow 函式顯示輸出影像。

時間效率的考量

為了評估模型的時間效率,可以在呼叫模型的 predict 函式之前和之後記錄時間。這樣可以計算出模型進行推理的時間。

使用不同的模型

可以嘗試使用不同的模型,例如根據 ResNet 的 SSD 模型,來比較其效能和時間效率。這些模型可以從 TensorFlow Hub 等模型函式庫中載入。

物體偵測技術:從SSD到R-CNN

在前面的章節中,我們討論了根據SSD(Single Shot Detector)的物體偵測模型,包括使用MobileNets和ResNet作為骨幹網路的實作。這些模型在實作物體偵測任務時表現出了不錯的效率和準確性。然而,除了SSD之外,還有另一種重要的物體偵測框架,即根據區域的卷積神經網路(R-CNN)。

SSD模型的推理時間

在使用SSD模型進行物體偵測時,我們關心的不僅是模型的準確性,還包括其推理時間。推理時間是指模型從接收輸入影像到輸出物體位置和類別的時間。使用根據ResNet的SSD模型時,我們觀察到其推理時間相比於根據MobileNets的SSD模型略長。這是因為ResNet的計算量更大,導致推理時間增加。

import time
from tensorflow import keras

# 載入模型
model = keras.models.load_model('resnet_ssd_model.h5')

# 載入影像
image = keras.preprocessing.image.load_img('image.jpg', target_size=(300, 300))

# 進行物體偵測
start_time = time.time()
predictions = model.predict(image)
end_time = time.time()

# 計算推理時間
inference_time = end_time - start_time
print(f'推理時間:{inference_time}秒')

R-CNN框架

R-CNN是一種兩階段的物體偵測框架,結合了卷積神經網路(CNN)和區域提議演算法的優點,實作了準確的物體定位和分類別。R-CNN的第一階段是區域提議,使用選擇性搜尋演算法在影像中找出潛在的物體區域。第二階段是特徵提取和物體分類別,對每個提議區域提取4096維的特徵向量,並使用CNN進行物體分類別。

區域提議

區域提議是R-CNN的第一階段,目的是在影像中找出可能包含物體的區域。這通常是使用選擇性搜尋演算法完成的,該演算法根據低階影像特徵(如顏色、紋理和強度)來找出潛在的物體區域。

特徵提取

在區域提議之後,R-CNN對每個提議區域進行特徵提取。這涉及使用CNN從每個區域提取4096維的特徵向量。這些特徵向量隨後被用於物體分類別。

邊界盒迴歸

除了物體分類別,R-CNN還進行邊界盒迴歸,以精煉提議區域的定位。這一步驟有助於提高物體定位的準確性。

綜觀技術發展脈絡,從早期的SSD模型到後來的R-CNN架構,物體偵測技術正持續演進。本文深入探討了SSD模型的優點、TensorFlow Hub的應用,以及OpenCV在影像處理中的重要性,並分析瞭如何載入預訓練模型、進行推理、處理輸出結果,甚至包含了標籤檔案的處理與邊界框的繪製。透過這些步驟,我們可以有效地運用SSD模型進行實時物體偵測,尤其在MobileNet等輕量級骨幹網路的支援下,更能兼顧效率與效能。然而,SSD模型並非完美無缺,其在處理小物件和密集場景時仍存在挑戰。相較之下,R-CNN框架透過兩階段的處理流程,先提議區域再進行分類別,能更精確地定位物體,特別在複雜場景下表現更佳。但R-CNN的計算成本相對較高,推理速度較慢,限制了其在實時應用中的佈署。展望未來,物體偵測技術將持續朝向更高效、更精確的方向發展,例如YOLO系列和Transformer-based模型的興起,預計將為此領域帶來新的突破。對於追求高準確率的應用,R-CNN或其變種仍是理想選擇;而對於注重速度的場景,SSD模型配合輕量級網路則更具優勢。技術團隊應根據實際需求,權衡速度與精確度,選擇最合適的物體偵測方案。