因為 OpenCV 在影像視覺中時常需要用到,所以現在嘗試在 AWS Lambda 中建立一層 OpenCV ,並將 Day 12 - 標籤圖片的方法與實作 這個練習,在 AWS Lambda 上完成。操作的流程如下:
步驟 1.打包 Python 的 OpenCV 函式庫
這個動作很重要,務必要在 Linux 環境下完成這個操作,不可以在 Windows/macOS,因為都會執行失敗,推論可能是因為 AWS Lambda 上執行 OpenCV 的 Container 是 Linux-based,但是這又很奇怪的是,其他 Python 的函式不會有這個問題。
登錄 Amazon Linux 2 的主機,執行下列程式,主要的操作內容是:
python3 -m venv opencv
cd opencv
. bin/activate
python -V
pip install pip -U
pip install opencv-python
cd lib/python3.7/
ln -s site-packages/ python
zip -r opencv37-45.zip python/
unzip -l opencv37-45.zip
目前這個壓縮包是針對 Python 3.7 且 opencv 的版本是 4.5.3.56,numpy 是 opencv 的相依包,所以會一併被安裝進來,整個檔案的大小是 72 MB左右
圖 1、Python OpenCV 壓縮包的相關版本
接著直接上傳壓縮檔到 S3,記得需要先完成 aws configure
的使用者認證。
aws s3 cp opencv37-45.zip s3://[S3存儲桶的名稱]
圖 2、Python OpenCV 壓縮包上傳到 S3
步驟 2.在 AWS Lambda 建立 OpenCV 層
進入 AWS Lambda 管理控制台,選擇建立 Layer,輸入 Layer 名稱,並上傳先前建立的壓縮檔,在選擇相容架構 x86_64,而相容的執行時間指的是希望可以在哪些版本的 python 中執行,只能選擇 Python 3.7 ,選其他版本會出錯,確定後按下 建立 鍵即完成建立 Layer,如下圖所示。
圖 3、建立 OpenCV Layer 設定畫面
步驟 3.打包程式以及圖片上傳到 S3
登錄 EC2 ,創建一個目錄,並將相關檔案放入該目錄中,壓縮後上傳到 S3 存儲桶內,相關指令如下, yoloDrawLabel.py 這個程式碼請參考 Day 12 - 標籤圖片的方法與實作 :
# 建立 lambda 專屬目錄,目錄名稱沒有強制要求
mkdir lambda
cd lambda
# 產生使用 opencv 的程式碼
vi yoloDrawLabel.py
mkdir labels images
# 上傳標籤所需要的圖片與標籤檔
aws s3 cp s3://[S3存儲桶的名稱]/00-frame-608x608-0001.jpg ./images
aws s3 cp s3://[S3存儲桶的名稱]/00-frame-0001.txt ./labels
# 執行程式,確保可以在虛擬環境中執行
python yoloDrawLabel.py
# 將所需要檔案壓縮並上傳到 S3
zip -r lambda.zip .
aws s3 cp lambda.zip s3://[S3存儲桶的名稱]
下圖為 EC2 執行畫面。
圖 4、在 EC2 中建立 Lambda 壓縮檔
./yoloDrawLabel.py
import cv2
# 設定輸入與輸出
inputLabelPath = './labels/00-frame-0001.txt'
inputImgPath = './images/00-frame-608x608-0001.jpg'
outputImgPath = './labels/00-frame-608x608-0001.jpg'
# 圖片大小固定為 608*608
img_w= img_h = 608
# 載入圖片
cv2image = cv2.imread(inputImgPath)
with open(inputLabelPath) as f:
for line in f:
line = line.strip() # 刪除多餘的空白
data = line.split() # 將 YOLO 一列的內容轉成一維陣列
# 將 YOLO 格式轉換為邊界框的左上角和右下角座標
bbox_width = float(data[3]) * img_w
bbox_height = float(data[4]) * img_h
center_x = float(data[1]) * img_w
center_y = float(data[2]) * img_h
min_x, min_y = center_x - (bbox_width / 2), center_y - (bbox_height / 2)
max_x, max_y = center_x + (bbox_width / 2), center_y + (bbox_height / 2)
print(min_x,min_y,max_x,max_y)
# 在圖片上寫上物件名稱
cv2.putText(cv2image, 'Altolamprologus compressiceps', (int(min_x), int(min_y-6)), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (255, 255, 255), 1, cv2.LINE_AA)
# 畫出邊界框
cv2.rectangle(cv2image, (int(min_x),int(min_y)), (int(max_x),int(max_y)), (0,255,255), 2)
# 將檔案另存新圖片檔
cv2.imwrite(r'{}'.format(outputImgPath), cv2image)
f.close()
步驟 4.在 AWS Lambda 執行
進入 AWS Lambda 管理控制台,選擇建立 Lambda 函數,設定內容如下圖所示。
圖 5、建立 Lambda 函數設定畫面
建立 Lambda 函數後,選擇進入 opencv45Func 函數的設定畫面,在畫面的最底端,為本函數新建 Layer,如下圖所示。
圖 6、為 Lambda 函數新增 Layer
進入新增 Layer 畫面後,選擇層來源為 自訂 Layer,接著選擇先前建立的 opencv45 函式庫層,如下圖所示。
圖 7、選擇 opencv45 函式庫層
上傳程式碼
我們已經把 Lambda 函數代碼上傳到 S3 ,只需在函數設定主畫面的右邊,可以找到一個 上傳於 按鈕,點擊後選擇 Amazon S3 位置,就可以指定位置,如 https://[S3存儲桶的名稱].s3.ap-southeast-1.amazonaws.com/lambda.zip,畫面如下所示。
圖 8、使用 S3 壓縮檔建立 Lambda 函數
打開 yoloDrawLabel.py 檔案,插入 AWS Lambda 的呼叫函數 handler ,修改完畢後記得點擊 Deploy,如下圖所示。
圖 9、修改 Lambda 函數
拉到畫面下方,修改 執行時間設定,將 處理常式 指定為 yoloDrawLabel.handler,如下圖所示。
圖 10、修改執行時間設定中的處理常式
透過點擊 Test 來執行 AWS Lambda 函數,第一次執行需要設定測試組態,不需任何更改,只需給定名稱即可。接著再點擊後,就會出現執行結果,輸出結果與在 EC2 上相同,輸出方塊框的左上角與右下角座標,如下圖所示。證明了 OpenCV 層已經正常運作。
圖 11、執行 AWS Lambda 函數