忘关烤箱了?我用 Python 和 OpenCV 来帮忙!

jopen 8年前

这篇文章应用计算机视觉和图像处理技术,展示了检测烤箱开关状态的过程。在生活中,有时你会粗心大意忘关烤箱之类的厨房电器,这潜在很大的危险。因此作者采用 Python 和 OpenCV,通过家庭摄像头获取的图像来自动识别烤箱是否开着,进而可以触发警报。

“我忘关烤箱了吗?”

这个问题常常会在最不方便的时候出现在你的脑子里。

有时是当你刚刚走出家门的时候。 有时是当你在上班路上的时候。 有时是当你坐在飞机上准备度个长假的时候……

解决这个问题的方法是多种多样的:

  1. 橡皮筋的方法
  2. 大声说或唱出来(就像  Samuel L. Jackson 一样)
  3. 当你离开家去度假的时候,给烤箱在内的电器列个清单或做个标记。 或者,我们也许有更好的做法……

在本教程中,我们会尝试利用技术手段解决这个问题。

Github 里有完整代码。

问题定义

对我们而言,我们需要确定一个信号,用于判断烤箱的开关状态。在我的厨房里,这个信号就是顶部标记着“烤箱开”字样的红色灯。

当红色灯亮的时候,烤箱是开着的:

当红色灯灭的时候,烤箱是关着的:

预备条件

确保你的电脑上安装了以下应用:

  1. OpenCV 3.0
  2. Python 2.7
  3. Numpy 1.9

安装 OpenCV3.0 和 Python 2.7

如果你尚未安装 OpenCV,请按照 Adrian Rosebrock 的完美教程,在 OSX 系统上安装 OpenCV 3.0 和 Python 2.7+。我在安装步骤里增加了一些自己的注释,以防你在 OSX 上编译 OpenCV 3.0时遇到问题。

步骤

如果你已经成功在你的环境中安装了 OpenCV,我们就可以开始判断烤箱开关的数据分析了。

加载需要的包

  1. argparse —— 参数处理库。
  2. numpy —— 高度优化的数值运算库。OpenCV 在数组结构中使用 numpy。
  3. cv2 —— OpenCV 中图像处理库。

Python

import argparse  import numpy as np  import cv2
import argparse  import numpyas np  import cv2
</div>

载入图片

Python

image = cv2.imread(image_path)
image = cv2.imread(image_path)
</div>

图片降噪

我们为了给图片降噪,需要对输入图片进行平滑处理。这样会更容易在图片中定位目标。使用 medianBlur 函数,把光圈大小定为 3 。数字越大意味着图像会越模糊。

Python

blur_image = cv2.medianBlur(image, 3)
blur_image = cv2.medianBlur(image, 3)
</div>

把图片颜 色转为 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)
</div>

执行结果如下图:

检测图 片中的颜色

为了检测我们想要的颜色,我们可以查看烤箱灯图片中颜色的直方图。

我们可以看出,红色在图片中占统治地位。红色有两个高峰 —— 一个幅度高,一个幅度低。这些颜色值转变为色度范围从 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])
</div>

结果如下:

接下来把这些图片合并在一起,以抓取所有红色色度。

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)
</div>

结果如下:

发现图片中的圆圈

现在我们的图片上仅有红色色度,接着我们需要判定红灯是否开启(即是否存在红色色度的那个圆圈)。我们需要在新图中发现圆圈,不过首先需要把图片转换成灰度图(因为 HoughCircles 函数的输入要求是灰度图)。

检测图片中的圆圈需要以下参数(使用 OpenCV中 的 HoughCircles 函数):

  1. 灰度图输入。
  2. HOUGH_GRADIENT 是用来检测圆圈的方法(目前仅有的一个方法)。
  3. 累加器和图片分辨率的反比。在本例中,为1.2。
  4. 待检测圆圈圆心的最小距离,本例中为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)
</div>

结果如下:

下一步

接下来还有很多可以做的,比如:

  1. 检测特定灯的开启,用以了解烤箱的真实状态。
  2. 建立一个服务以便远程检查烤箱状态。
  3. 把该功能加入树莓派(译者注:基于Linux的迷你开发板),我们就拥有可以警告烤箱关闭与否的小型设备。

全部样例代码可以在 Github 中找到。 写于2015年,8月2日

</div>

来自: http://python.jobbole.com/84127/