company_banner

Intel OpenVINO на Raspberry Pi: урожай 2018 года


    Писать про программирование можно не только прозой, но и стихами. Последнее, конечно, случается не часто — скажем, в блоге Intel такое бывало чуть менее, чем никогда. Однако в порядке эксперимента сегодня мы решили позволить себе; как это получилось — решать вам. Итак...


    В последнем квартале уходящего года,
    А если быть точным, на прошлой неделе,
    Разработчики Intel представили новый
    Релиз OpenVINO toolkit на software.


    Что нового сделано — обратитесь к changelog'ам,
    Мне точным в деталях быть не дано,
    Я в этом посте расскажу лишь немного:
    Про зрение, Intel и малиновое вино.


    ***


    OpenVINO по сути — набор инструментов,
    Библиотек и примеров решения
    С особым ускорением на железе Интела
    Популярных задач компьютерного зрения.


    Кто не слышал про computer vision -
    Это область компьютерных наук,
    Заставляющая понимать машину,
    Подобно человеку, мир вокруг.


    Источник информации, в основном, изображения,
    А проблема — создать алгоритм
    Для извлечения полезных признаков
    И принятию решений по ним.


    ***


    Первая в нашем мини-обзоре — библиотека OpenCV,
    Как часто зовётся, традиционного
    Машинного зрения и обучения,
    Читающей с камеры и на экране рисующей,
    Кросс-платформенной и на GitHub’е живущей,
    Набравшая на момент написания 30502 звезды.


    В пакете для Raspberry мы так же найдём
    Публичную OpenCV, а с ней
    NEON оптимизации, обёртки в Python,
    GStreamer для камер и для окон GTK.



    ***


    Вот уже лет семь на свете
    Для решения наших задач
    Применяют глубокие нейронные сети,
    Те, что с учителем нужно обучать.


    Caffe, PyTorch — всё это про тренинг,
    Порой занимающим пару недель.
    OpenVINO решает вторую проблему:
    Запуск обученных сеток, как можно быстрей.


    Из лучших решений для многих платформ,
    Для известных сценариев, нужд и ресурсов,
    В OpenVINO deep learning — отдельным движком,
    С одним интерфейсом на разных устройствах.


    ***


    Для работы у вас инструментария
    Установите Raspbian 9 на Raspberry Pi,
    Подключите Movidius стик, блок питания,
    Проверьте что версия CPU не ниже семи.


    Подробнее читайте в соответствующем гайде,
    А в качестве демо предлагаю код,
    Работающий с камерой и выключающий
    По направлению взгляда светодиод.


    Скачайте две сети: для лиц нахождения
    И предсказаний головы положения,
    Используйте USB камеру и обратите внимание,
    Что в коде пин номер 2 по умолчанию.


    ***


    Всем тем посвящается, кто увлеченно
    Над нашим проектом работал весь год.
    Пусть только ускоряется всё в наступающем,
    OpenVINO на Raspberry — тот самый IoT!


    import cv2 as cv
    from gpiozero import LED
    from math import cos, sin, pi
    
    winName = 'OpenVINO on Raspberry Pi'
    
    cv.namedWindow(winName, cv.WINDOW_NORMAL)
    
    faceDetectionNet = cv.dnn.readNet('face-detection-retail-0004.xml',
                                      'face-detection-retail-0004.bin')
    headPoseNet = cv.dnn.readNet('head-pose-estimation-adas-0001.xml',
                                 'head-pose-estimation-adas-0001.bin')
    faceDetectionNet.setPreferableTarget(cv.dnn.DNN_TARGET_MYRIAD)
    headPoseNet.setPreferableTarget(cv.dnn.DNN_TARGET_MYRIAD)
    
    cap = cv.VideoCapture(0)
    led = LED(2)
    led.on()
    
    while cv.waitKey(1) != 27:
        hasFrame, frame = cap.read()
        if not hasFrame:
            break
    
        frameHeight, frameWidth = frame.shape[0], frame.shape[1]
    
        # Detect faces on the image.
        blob = cv.dnn.blobFromImage(frame, size=(300, 300), ddepth=cv.CV_8U)
        faceDetectionNet.setInput(blob)
        detections = faceDetectionNet.forward()
    
        for detection in detections.reshape(-1, 7):
            confidence = float(detection[2])
            if confidence > 0.5:
                xmin = int(detection[3] * frameWidth)
                ymin = int(detection[4] * frameHeight)
                xmax = int(detection[5] * frameWidth)
                ymax = int(detection[6] * frameHeight)
    
                xmax = max(1, min(xmax, frameWidth - 1))
                ymax = max(1, min(ymax, frameHeight - 1))
                xmin = max(0, min(xmin, xmax - 1))
                ymin = max(0, min(ymin, ymax - 1))
    
                # Run head pose estimation network.
                face = frame[ymin:ymax+1, xmin:xmax+1]
                blob = cv.dnn.blobFromImage(face, size=(60, 60), ddepth=cv.CV_8U)
    
                headPoseNet.setInput(blob)
                headPose = headPoseNet.forward(['angle_p_fc', 'angle_r_fc', 'angle_y_fc'])
    
                p, r, y = headPose[0][0], headPose[1][0], headPose[2][0]
                cos_r = cos(r * pi / 180)
                sin_r = sin(r * pi / 180)
                sin_y = sin(y * pi / 180)
                cos_y = cos(y * pi / 180)
                sin_p = sin(p * pi / 180)
                cos_p = cos(p * pi / 180)
    
                x = int((xmin + xmax) / 2)
                y = int((ymin + ymax) / 2)
                # center to right
                cv.line(frame, (x,y), (x+int(50*(cos_r*cos_y+sin_y*sin_p*sin_r)), y+int(50*cos_p*sin_r)), (0, 0, 255), thickness=3)
                # center to top
                cv.line(frame, (x, y), (x+int(50*(cos_r*sin_y*sin_p+cos_y*sin_r)), y-int(50*cos_p*cos_r)), (0, 255, 0), thickness=3)
                # center to forward
                cv.line(frame, (x, y), (x + int(50*sin_y*cos_p), y + int(50*sin_p)), (255, 0, 0), thickness=3)
    
                cv.rectangle(frame, (xmin, ymin), (xmax, ymax), (0, 255, 255))
    
                if abs(cos_y * cos_p) > 0.9:
                    cv.putText(frame, 'FORWARD', (0, 30), cv.FONT_HERSHEY_SIMPLEX, 1.0, (0, 255, 0), thickness=2)
                    led.off()
                else:
                    led.on()
    
        cv.imshow(winName, frame)


    • +13
    • 8,4k
    • 8
    Intel
    193,00
    Компания
    Поделиться публикацией

    Комментарии 8

      +8
      Извините, но реально сложно воспринимать. Хорошо хоть код в прозе)
        +3
         Внимайте мне все
         священные роды,
         великие с малыми
         Хеймдалля дети!
         Один, ты хочешь,
         чтоб я рассказала
         о прошлом всех сущих,
         о древнем, что помню
          +4
          Автор, чего вам точно не дано, так это стихи писать. Никогда больше так не делайте. Они ужасны.
            +4
            Тема реально интересная, но как же тяжело читать! Автор, не делайте так больше никогда, пожалуйста.
              +2
              Автор, это забавно, но очень просим дальше деать в прозе. Стихи здесь неуместны
                +2
                С каким разрешением и каким максимально FPS удаётся положение головы оценивать?
                Была бы интересна оценка — с Мовидиусом и без.
                  +1

                  CopterSpace, В данном случае у нас алгоритм состоит из двух частей: нахождение лиц и затем, по лицу, определить положение головы. Все найденные лица вырезаются из кадра и приводятся к единому размеру (60x60). То есть если говорить про качество — важно отдельно оценивать детектор и предсказатель углов.


                  Про сравнение с Мовидиусом и без. Две эти сети сохранены в формате, который можно запускать только через OpenVINO — а это значит, что только на железе Intel (CPU, GPU, FPGA, VPU (Movidius)). Для Raspberry Pi доступен только режим запуска на Movidius (или через OpenCV, но уже не Intel сетей, а других публичных). Альтернатива — попробовать взять публичную сеть и запустить как на CPU, так и на Movidius (через тот же OpenCV).


                  Конкретно для этих двух сетей, этого скрипта, и того, что у меня лежит дома (Movidius Neural Compute Stick первой версии и Raspberry Pi 2 model B) — детектор отрабатывает за 72-75 миллисекунд (около 14 FPS), предсказание углов — 10-11 миллисекунд (около 100 FPS). Детектор можно разогнать, подавая ему на вход изображение размера не 300x300, а меньше. Мы (OpenCV) так сделали для JavaScript примера с похожей сетью (там 128x96 вход). Какой размер брать — зависит от потребностей в балансе качества против скорости.


                  Хочу обратить внимание, что эти числа можно воспроизвести только указывая ddepth=cv.CV_8U, что значит, что на стик по USB отправляются не FP32, а U8, которые конвертируются уже на девайсе. Такой трюк необходим потому, что на RPI USB 2.0 и чем меньше отсылаем данных — тем быстрее общий FPS.

                  0
                  Очень здоровская подача! Рифмы корявые, ритм хромой, но это комизма лишь добавляет. Пару четверостиший выучу, чтоб начинать декламировать в неловких ситуациях. Автору могу пожелать не терять энтузиазма — побольше тренироваться слагать стихи и уметь с помощью них описать возню с железом и кодинг!

                  Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                  Самое читаемое