从树莓派摄像头获取一帧直接送到inception做推理

这周用树莓派做了个小项目,期间遇到的问题可真不少,所幸一个一个都解决了。中间走了不少弯路,浪费了很多时间,但同时也增进了对python,tensorflow,opencv,PIL,picamera还有inception,ssd-mobilenet的了解,这里记录一下进阶的过程,免得日后忘了。
问题一:为了获得更高的执行效率,要从摄像头获取一帧直接送到inception做推理。以tfClassifier为例,常规的做法是用从硬盘读一个图片,送给DecodeJpeg/contents:0,然后进行推理。为达到我的目的,这个问题就可以被拆成若干个个小问题:

1. DecodeJpeg/contents:0的输入是什么格式;
2. DecodeJpeg/contents:0的输出是什么格式;
3. 送到哪个节点了;
4. 摄像头如何捕获一帧;
5. 捕获的帧是什么格式;
6. 帧的格式和DecodeJpeg/contents:0的输出的格式一样吗。

对应的解答

  1. DecodeJpeg/contents:0的输入是由gfile.FastGFile读取的。image_data = tf.gfile.FastGFile(image, 'rb').read()读取的是二进制文件,没有经过解码。也可以直接用open().read()来替换。
  2. DecodeJpeg/contents:0调用的是图片解码函数tf.image.decode_jpeg。由文档可知,输出为3维张量,张量格式为[height,width, channels],channels格式为RGB,数据格式为uint8。这里要注意opencv的imread()函数同时读取和解码,解码后的格式也是[height, width, channels],但是channels格式为BGR。
  3. 用tensorboard打开模型图,可以看到DecodeJpeg/contents:0输出给了Cast:0的输入。
  4. 树莓派的原生摄像头用picamera操作非常方便。有以下官方文档可以参考,摄像头官方文档,树莓派Gettingstarted with picamera,及其中文翻译,树莓派Raspberry Pi Camera Module。我没有细读文档,二是直接参考了Adrian Rosebrock的博文Accessing the Raspberry Pi Camera with OpenCV and Python。
  5. Adrian Rosebrock的博文里有非常详细的代码和解释,如下图。可以看出capture_continuous函数能捕获帧,没有经过压缩(即和解码后的一样),格式是Numpy
    array格式,并可以指定RGB的顺序。
    从树莓派摄像头获取一帧直接送到inception做推理_第1张图片
  6. 我先用一张图片做测试,用opencv的imread()函数读并解压一张图片,把channels从BGR改成RGB,然后直接feed给Cast:0,能成功分类。然后再用摄像头捕获的帧试一试,也成功了。至此证明帧的格式和DecodeJpeg/contents:0的输出的格式是一样,只需要指定channels的顺序为RGB。

树莓派picamera库抓图到内存

想实时处理树莓派摄像头捕获的照片,花了差不多一天的时间才搞定。这里记录下收获。
方案一:用picamera捕获一张图到文件(’foo.jpg’),再把开文件内容读到image_data进行处理。代码如下:

from time import sleep
from picamera import PiCamera

camera = PiCamera()
camera.resolution = (1024, 768)
camera.start_preview()
# Camera warm-up time
sleep(2)
camera.capture('foo.jpg')
# Read in the image_data
image_data = open('foo.jpg', 'rb').read()

方案二:为了提高处理的效率,用picamera从树莓派原生摄像头模块直接抓图到内存BytesIO对象my_stream,然后调用getvalue()方法读取图像内容进行处理,

from io import BytesIO
from time import sleep
from picamera import PiCamera

# Create an in-memory stream
my_stream = BytesIO()
camera = PiCamera()
camera.start_preview()
# Camera warm-up time
sleep(2)
camera.capture(my_stream, 'jpeg')
image_data = my_stream.getvalue()

之所以不用Opencv,是因为picamera运行效率更高。

你可能感兴趣的:(从树莓派摄像头获取一帧直接送到inception做推理)