忘關烤箱了?我用 Python 和 OpenCV 來幫忙!
這篇文章應用計算機視覺和圖像處理技術,展示了檢測烤箱開關狀態的過程。在生活中,有時你會粗心大意忘關烤箱之類的廚房電器,這潛在很大的危險。因此作者采用 Python 和 OpenCV,通過家庭攝像頭獲取的圖像來自動識別烤箱是否開著,進而可以觸發警報。
“我忘關烤箱了嗎?”
這個問題常常會在最不方便的時候出現在你的腦子里。
有時是當你剛剛走出家門的時候。 有時是當你在上班路上的時候。 有時是當你坐在飛機上準備度個長假的時候……
解決這個問題的方法是多種多樣的:
- 橡皮筋的方法
- 大聲說或唱出來(就像 Samuel L. Jackson 一樣)
- 當你離開家去度假的時候,給烤箱在內的電器列個清單或做個標記。 或者,我們也許有更好的做法……
在本教程中,我們會嘗試利用技術手段解決這個問題。
Github 里有完整代碼。
問題定義
對我們而言,我們需要確定一個信號,用于判斷烤箱的開關狀態。在我的廚房里,這個信號就是頂部標記著“烤箱開”字樣的紅色燈。
當紅色燈亮的時候,烤箱是開著的:
當紅色燈滅的時候,烤箱是關著的:
預備條件
確保你的電腦上安裝了以下應用:
- OpenCV 3.0
- Python 2.7
- Numpy 1.9
安裝 OpenCV3.0 和 Python 2.7
如果你尚未安裝 OpenCV,請按照 Adrian Rosebrock 的完美教程,在 OSX 系統上安裝 OpenCV 3.0 和 Python 2.7+。我在安裝步驟里增加了一些自己的注釋,以防你在 OSX 上編譯 OpenCV 3.0時遇到問題。
步驟
如果你已經成功在你的環境中安裝了 OpenCV,我們就可以開始判斷烤箱開關的數據分析了。
加載需要的包
- argparse —— 參數處理庫。
- numpy —— 高度優化的數值運算庫。OpenCV 在數組結構中使用 numpy。
- cv2 —— OpenCV 中圖像處理庫。
Python
import argparse import numpy as np import cv2
import argparse import numpyas np import cv2
載入圖片
Python
image = cv2.imread(image_path)
image = cv2.imread(image_path)
圖片降噪
我們為了給圖片降噪,需要對輸入圖片進行平滑處理。這樣會更容易在圖片中定位目標。使用 medianBlur 函數,把光圈大小定為 3 。數字越大意味著圖像會越模糊。
Python
blur_image = cv2.medianBlur(image, 3)
blur_image = cv2.medianBlur(image, 3)
把圖片顏 色轉為 HSV 格式
HSV —— 色度、飽和度和純度(亮度)。HSV 可以讓我們提取出一個彩色對象,因為它比 BGR 格式(譯者注:與我們常說的RBG色彩模型類似,三個字母分別代表紅藍綠三色)更容易表征顏色。
把圖片轉為 HSV 格式可以讓我們通過色度(一個值而不是三個值),來確定圖片中的一個顏色。
以下是實現方式:
Python
hsv_image = cv2.cvtColor(blur_image, cv2.COLOR_BGR2HSV)
hsv_image = cv2.cvtColor(blur_image, cv2.COLOR_BGR2HSV)
執行結果如下圖:
檢測圖 片中的顏色
為了檢測我們想要的顏色,我們可以查看烤箱燈圖片中顏色的直方圖。
我們可以看出,紅色在圖片中占統治地位。紅色有兩個高峰 —— 一個幅度高,一個幅度低。這些顏色值轉變為色度范圍從 0 到10,以及從 160 到 180 (針對紅色)。
在 HSV 圖片中針對每一個色度范圍,我們可以創建一個遮罩,來去掉所有不在選定范圍的無關顏色。
Python
def create_hue_mask(image, lower_color, upper_color): lower = np.array(lower_color, np.uint8) upper = np.array(upper_color, np.uint8) # Create a mask from the colors mask = cv2.inRange(image, lower, upper) output_image = cv2.bitwise_and(image, image, mask = mask) return output_image # Get lower red hue lower_red_hue = create_hue_mask(hsv_image, [0, 100, 100], [10, 255, 255]) # Get higher red hue higher_red_hue = create_hue_mask(hsv_image, [160, 100, 100], [179, 255, 255])
def create_hue_mask(image, lower_color, upper_color): lower = np.array(lower_color, np.uint8) upper = np.array(upper_color, np.uint8) # Create a mask from the colors mask = cv2.inRange(image, lower, upper) output_image = cv2.bitwise_and(image, image, mask = mask) return output_image # Get lower red hue lower_red_hue = create_hue_mask(hsv_image, [0, 100, 100], [10, 255, 255]) # Get higher red hue higher_red_hue = create_hue_mask(hsv_image, [160, 100, 100], [179, 255, 255])
結果如下:
接下來把這些圖片合并在一起,以抓取所有紅色色度。
Python
full_image = cv2.addWeighted(lower_red_hue, 1.0, higher_red_hue, 1.0, 0.0)
full_image = cv2.addWeighted(lower_red_hue, 1.0, higher_red_hue, 1.0, 0.0)
結果如下:
發現圖片中的圓圈
現在我們的圖片上僅有紅色色度,接著我們需要判定紅燈是否開啟(即是否存在紅色色度的那個圓圈)。我們需要在新圖中發現圓圈,不過首先需要把圖片轉換成灰度圖(因為 HoughCircles 函數的輸入要求是灰度圖)。
檢測圖片中的圓圈需要以下參數(使用 OpenCV中 的 HoughCircles 函數):
- 灰度圖輸入。
- HOUGH_GRADIENT 是用來檢測圓圈的方法(目前僅有的一個方法)。
- 累加器和圖片分辨率的反比。在本例中,為1.2。
- 待檢測圓圈圓心的最小距離,本例中為100。
Python
#Convert image to grayscale image_gray = cv2.cvtColor(full_image, cv2.COLOR_BGR2GRAY) #Find circles in the image circles = cv2.HoughCircles(image_gray, cv2.HOUGH_GRADIENT, 1.2, 100)
#Convert image to grayscale image_gray = cv2.cvtColor(full_image, cv2.COLOR_BGR2GRAY) #Find circles in the image circles = cv2.HoughCircles(image_gray, cv2.HOUGH_GRADIENT, 1.2, 100)
結果
此時就可以檢查是否有圓圈了。如果有就意味著至少有一個烤箱燈亮著。如果找不到圓圈就意味著沒有燈亮,烤箱關著。
為了證明此結論,我們可以用下述代碼在原圖中畫圓圈:
Python
# Draw the circles on the original image circles = np.round(circles[0, :]).astype("int") for (center_x, center_y, radius) in circles: cv2.circle(image, (center_x, center_y), radius, (0, 255, 0), 4)
# Draw the circles on the original image circles = np.round(circles[0, :]).astype("int") for (center_x, center_y, radius) in circles: cv2.circle(image, (center_x, center_y), radius, (0, 255, 0), 4)
結果如下:
下一步
接下來還有很多可以做的,比如:
- 檢測特定燈的開啟,用以了解烤箱的真實狀態。
- 建立一個服務以便遠程檢查烤箱狀態。
- 把該功能加入樹莓派(譯者注:基于Linux的迷你開發板),我們就擁有可以警告烤箱關閉與否的小型設備。
全部樣例代碼可以在 Github 中找到。 寫于2015年,8月2日