DesignSpark Electrical Logolinkedin
菜单 搜寻
提问问题

AI使用Pidentifier进行对象识别!

使用Pi 3 Model B,Pi Camera,Intel Movidius NCS,DesignSpark Pmod HAT和Digilent OLED Pmod构建基于树莓派的对象识别设备

想想人工智能和深度神经网络(DNNs)是专家工程师,科学家和数学家的储备吗?那么,创建新的神经网络可能并不是一件容易的事,而训练它们可能需要大量的时间和资源。然而幸运的是,对于我们来说,我们可以利用已经接受过有用图像集培训的现有网络,以及Movidius NCS和SDK,相对容易地构建简单的应用程序,并使用这些应用程序,使用紧凑的低功耗计算平台作为树莓派。
本文将介绍如何快速整合一个集成摄像头和一个紧凑型OLED模块的自包含系统,该系统将在NCS上运行的GoogLeNet上捕获图像并将其卸载,然后在显示顶级结果OLED模块。

硬件

这个项目使用一个运行Raspbian Stretch的Raspberry Pi 3 Model B和官方的Raspberry Pi Camera。除此之外,还有英特尔Movidius NCS,我们也有DesignSpark Pmod HAT和Digilent PmodOLEDrgb来显示结果。

安装了Raspbian并启动了Pi之后,通过升级到最新版本的打包软件开始是一个不错的主意

pi@pidentifier:~$ sudo apt-get update
pi@pidentifier:~$ sudo apt-get dist-upgrade

我们还需要为OLED模块启用相机接口和SPI

pi@pidentifier:~$ sudo raspi-config
  • 选项5 - 接口
  • P1 - 相机
  • 启用→是
  • 选项5 - 接口
  • P4 - SPI
  • 启用→是

软件依赖关系

我们可以通过O / S包管理系统获得大部分的软件依赖关系。

pi@pidentifier:~$ sudo apt-get install -y build-essential git libusb-1.0-0-dev libprotobuf-dev libleveldb-dev libsnappy-dev libopencv-dev libhdf5-serial-dev protobuf-compiler libatlas-base-dev git automake byacc lsb-release cmake libgflags-dev libgoogle-glog-dev liblmdb-dev swig3.0 graphviz libxslt-dev libxml2-dev gfortran python3-dev python3-pip python3-setuptools python3-markdown python3-pillow python3-yaml python3-pygraphviz python3-h5py python3-nose python3-lxml python3-matplotlib python3-numpy python3-protobuf python3-dateutil python3-skimage python3-scipy python3-six python3-networkx libfreetype6-dev libjpeg-dev python3-gst-1.0 python3-picamera

接下来,使用Python包管理器来安装对OpenCV的支持。

pi@pidentifier:~$ sudo pip3 install opencv-python

只安装Movidius NC SDK的API组件。请注意,可能在Raspberry Pi上安装完整的SDK,但通常不建议这样做,因为在PC上进行必要的编译,然后复制二进制图形文件更为迅速。

pi@pidentifier:~$ mkdir workspace
pi@pidentifier:~$ cd workspace
pi@pidentifier:~$ git clone https://github.com/movidius/ncsdk
pi@pidentifier:~$ cd ncsdk/api/src
pi@pidentifier:~$ make
pi@pidentifier:~$ sudo make install

DesignSpark Pmod HAT支持库可以通过一个命令来安装。

pi@pidentifier:~$ sudo pip3 install designspark.pmod

最后,需要在运行Ubuntu的另一台计算机上完整安装Movidius NC SDK,以便我们可以编译树莓派上使用的模型。

user@laptop:~$ mkdir workspace
user@laptop:~$ cd workspace
user@laptop:~$ git clone https://github.com/movidius/ncsdk 
user@laptop:~$ cd
user@laptop:~$ sudo make install

测试硬件

如果我们开始测试Pi摄像头是否按预期工作。

pi@pidentifier:~$ raspivid -d

这应该在屏幕上显示视频。

接下来,我们可以运行NCS的Hello World来确认它的运行

pi@pidentifier:~$ cd ~/workspace
pi@pidentifier:~$ git clone https://github.com/movidius/ncappzoo
pi@pidentifier:~$ python3 ncappzoo/apps/hello_ncs_py/hello_ncs.py

如果我们用下面的内容创建一个名为helloOLED.py的文件,测试PmodOLEDrgb:

from DesignSpark.Pmod.HAT import createPmod
from luma.core.render import canvas
from luma.oled.device import ssd1331

if __name__ == '__main__':
    try:
        oled = createPmod('OLEDrgb','JA')
        device = oled.getDevice()
        
        with canvas(device) as draw:
            draw.rectangle(device.bounding_box, outline="white", fill="black")
            draw.text((16,20), "Hello, World!", fill="white")
    
        while True:
            pass
    except KeyboardInterrupt:
        pass
    finally:
        oled.cleanup()

然后执行它

pi@pidentifier:~$ python3 helloOLED.py

Pmod模块的文档以及其他示例可以在ReadTheDocs上找到

模型编译

我们将使用一个训练有素的模型,它是在GoogLeNet论文中描述的模型的复制。但首先,这需要在Ubuntu机器上进行编译,在那里我们执行完整的NC SDK安装。我们将同时编译随SDK提供的所​​有示例 - 并注意在编译期间必须将NC插入此计算机。

user@laptop:~$ cd workspace/ncsdk
user@laptop:~$ make examples

应用

现在开始创建应用程序。
我们需要从Ubuntu计算机到Raspberry Pi之间复制GoogLeNet模型的新编译的二进制图形。

user@laptop:~$ scp workspace/ncsdk/examples/caffe/GoogLeNet/graph \
user@laptop:~$ pi@pidentifier.local:workspace/ncappzoo/caffe/GoogLeNet/

接下来,如果我们使用文本编辑器在Raspberry Pi上创建一个名为pidentify的新文件(用你最喜欢的编辑器替换“vi”):

pi@pidentifier:~$ vi pidentify

我们可以通过输入以下内容来导入所需的Python库

#!/usr/bin/python3
import os
import sys
import time
import numpy

import picamera

import mvnc.mvncapi as mvnc
import skimage
from skimage import io, transform

from DesignSpark.Pmod.HAT import createPmod
from luma.core.render import canvas
from luma.oled.device import ssd1331

接下来,我们需要定义一些NCS输入参数

NCAPPZOO_PATH           = os.path.expanduser( '~/workspace/ncappzoo' )
GRAPH_PATH              = NCAPPZOO_PATH + '/caffe/GoogLeNet/graph'
IMAGE_PATH              = '/tmp/i-spy.jpg'
IMAGE_MEAN              = [ 104.00698793, 116.66876762, 122.67891434]
IMAGE_STDDEV            = 1
IMAGE_DIM               = ( 224, 224 )

NETWORK_STAT_TXT = NCAPPZOO_PATH + '/apps/stream_infer/googlenet_stat.txt'
NETWORK_CATEGORIES_TXT = NCAPPZOO_PATH + '/apps/stream_infer/googlenet_categories.txt'

请注意,如果要使用不同的神经网络,这是我们将进行更改的地方。
以下两行将创建一个树莓派相机实例配置正确的分辨率为我们的神经网络

camera = picamera.PiCamera()
camera.resolution = IMAGE_DIM

接下来,我们打开NCS并获取设备句柄

ncsdevices = mvnc.EnumerateDevices()
if len( ncsdevices ) == 0:
        print( 'No NCS devices found' )
        quit()

ncs = mvnc.Device( ncsdevices[0] )
ncs.OpenDevice()

我们还需要创建一个DesignSpark Pmod OLEDrgb实例

pmoddev = createPmod('OLEDrgb','JA')
oled = pmoddev.getDevice()

通过最初的设备设置,我们现在可以将图形文件加载到NCS上

with open( GRAPH_PATH, mode='rb' ) as f:
        blob = f.read()

graph = ncs.AllocateGraph( blob )

我们可以加载网络类别

with open(NETWORK_CATEGORIES_TXT, 'r') as f:
    for line in f:
        cat = line.split('\n')[0]
        if cat != 'classes':
            gNetworkCategories.append(cat)
    f.close()

last = len(gNetworkCategories)-1

我们将创建一个函数将图像卸载到NCS,运行推理并返回最高结果

def getTopInference(img):
    img = print_img = skimage.io.imread( IMAGE_PATH )
    img = skimage.transform.resize( img, IMAGE_DIM, preserve_range=True )

    img = img[:, :, ::-1]

    img = img.astype( numpy.float32 )
    img = ( img - IMAGE_MEAN ) * IMAGE_STDDEV

    graph.LoadTensor( img.astype( numpy.float16 ), 'user object' )

    output, userobj = graph.GetResult()
    order = output.argsort()
    top = gNetworkCategories[order[last-0]]

    return top

还有一个简单的功能就是把文本写到PmodOLEDrgb模块的屏幕上

def display(message):
    with canvas(oled) as draw:
        draw.text((16,20), message, fill="white")

最后是主循环

try:
    while True:
        camera.capture(IMAGE_PATH)
        thing = getTopInference(IMAGE_PATH)
        display(thing)
        time.sleep(2)

except KeyboardInterrupt:
        pass

finally:
        graph.DeallocateGraph()
        ncs.CloseDevice()
        oled.cleanup()

这将捕捉一个图像,显示最高推断,暂停2秒,然后重复

如果我们现在保存该文件并使其可执行

pi@pidentifier:~$ chmod +x pidentify

考验它

最后,令人兴奋的部分:对它进行所有的测试!

pi@pidentifier:~$ ./pidentify

在短暂的延迟之后,现在应该显示最高推断,每隔几秒更新一次。在这一点上,重要的是要注意,网络是由1000个类别中的1个图像进行训练的,所以它可以分类的是有限的。同样,前1的推断准确度 - 我们只显示最高的结果 - 是68.7%,前5位的推断准确率高达88.9%

潜在的改进

可以快速地将一个简单的应用程序集成到一个简单的应用程序中,这个应用程序集成了一个Raspberry Pi摄像机,Intel Movidius NCS和一个Pmod HAT以及OLEDrgb显示器,这要归功于Python支持这些和提供的示例。进一步的实验肯定有改进的空间和乐趣。这可能包括,例如:

  • 尝试不同的网络,这应该只是复制编译的二进制图形文件并相应地更新NCS输入参数
  • 使用视频流而不是仍然捕获。 NC应用程序动物园包括一个stream_infer应用程序的例子,可以作为这个基础
  • 使用多个NCS,NC应用程序动物园再次包含示例代码
  • 优化相机捕捉参数
  • 更好地显示文本的格式

或者,即使冒险,也可以在自己的数据/图像上操练一个模型!

Andrew Back

Open source (hardware and software!) advocate, Treasurer and Director of the Free and Open Source Silicon Foundation, organiser of Wuthering Bytes technology festival and founder of the Open Source Hardware User Group.

22 Jan 2018, 11:16