В этом руководстве обсуждается создание системы наблюдения с использованием USB-камеры, подключенной к Raspberry Pi (RPi), которая подключается к ПК с помощью беспроводного интерфейса. PyGame используется для доступа к камере и захвата изображений, которые хранятся на SD-карте RPi. Для сцены создается фоновая модель, чтобы обнаружить изменения по сравнению с состоянием по умолчанию. Простая схема, подключенная к контактам GPIO, загорается светодиодом в качестве индикации таких состояний.

Учебник состоит из следующих шагов:

  1. Подключение RPi к ПК по беспроводному интерфейсу.
  2. Подключение USB камеры к RPi.
  3. Захват изображений с помощью PyGame.
  4. Построение фоновой модели.
  5. Обнаружение изменений в фоновой модели.
  6. Построение простой схемы, которая зажигает светодиод, когда происходит изменение.

В руководстве предполагается, что у считывателя есть ПК, подключенный к беспроводной сети, а RPi подключен к коммутатору с помощью интерфейса Ethernet. Для выполнения такой работы прочтите руководство под названием «Создание классификатора изображений, работающего на Raspberry Pi», которое доступно по этой ссылке:

Https://www.linkedin.com/pulse/building-image-classifier-running-raspberry-pi-ahmed-gad

Вы должны быть в состоянии узнать IP-адреса устройств с помощью программного обеспечения, такого как «Advanced IP Scanner», и ознакомиться с установкой SSH-соединения с помощью программного обеспечения MobaXterm. После этого мы можем приступить к обсуждению каждого из вышеперечисленных шагов.

1. Подключение RPi к ПК с помощью беспроводного интерфейса.

В предыдущем руководстве «Создание классификатора изображений, работающего на Raspberry Pi» мы построили сеть с тремя подключенными устройствами: RPi, коммутатором и ПК. RPI был подключен к коммутатору с помощью интерфейса Ethernet, но ПК подключен к коммутатору с помощью беспроводного интерфейса. В этом руководстве мы изменим такую ​​сеть, используя беспроводной интерфейс RPi для подключения к коммутатору. Это делает сеть полностью беспроводной и позволяет избежать ограничений проводов.

Чтобы использовать беспроводной интерфейс RPi, необходимо его настроить. По этой причине мы по-прежнему будем использовать соединение, установленное с помощью интерфейса Ethernet, для настройки беспроводного интерфейса. Используя DHCP в коммутаторе, интерфейсу Ethernet RPi будет присвоен IPv4-адрес. Затем такой адрес можно использовать для установления соединения через защищенную оболочку (SSH). Вы можете обратиться к предыдущему руководству для получения дополнительных сведений об установке соединения.

Внутри сеанса SSH, созданного с помощью MobaXterm, мы можем начать настройку беспроводного интерфейса, используя либо команды терминала, либо графический интерфейс ОС Raspbian. Оба способа просты.

Используя команды терминала, мы начнем со сканирования доступных беспроводных сетей, чтобы найти их идентификаторы набора услуг (SSID). Это делается с помощью следующей команды:

pi@raspberrypi:~ $ sudo iwlist wlan0 scan

Первые несколько строк вывода этой команды приведены на следующем рисунке. SSID целевой беспроводной сети - «TEData_864A». Обратите внимание, что вам не нужно использовать переключатель для подключения ПК к RPi. Используя смартфон, мы можем создать точку доступа для их подключения.

Зная SSID целевой сети, мы можем использовать его для настройки беспроводного интерфейса. Такая конфигурация существует внутри файла, к которому можно получить доступ с помощью следующей команды:

pi@raspberrypi:~ $ sudo nano /etc/wpa_supplicant/wpa_supplicant.conf

Файл откроется внутри терминала. Используя стрелку вниз, вернитесь в конец файла, чтобы записать конфигурацию сети. Для этого нужно записать SSID и пароль сети следующим образом:

network={
ssid=”TEData_864A”
psk=”YOUR_NETWOK_PASSWORD”
}

После этого нажмите CTRL + X, чтобы выйти из файла, а затем нажмите Y, чтобы сохранить изменения. В моем случае я настроил 2 сети, и, таким образом, содержимое файла имеет две настроенные сети, как показано на следующем рисунке.

Возможно, вам придется изменить статус беспроводного интерфейса с «вверх» на «вниз», чтобы снова применить такие конфигурации. Это делается с помощью этих двух команд:

pi@raspberry:~ $ sudo ifdown wlan0
pi@raspberry:~ $ sudo ifup wlan0

Чтобы проверить, правильно ли настроен беспроводной интерфейс, введите команду «ifconfig», чтобы получить конфигурацию интерфейса.

pi@raspberry:~ $ ifconfig

Согласно выходным данным этой команды, беспроводному интерфейсу назначается IPv4-адрес 192.168.1.8. Вот как настроить беспроводное соединение с помощью команд терминала.

Мы можем сделать то же самое, используя графический интерфейс ОС, доступ к которому можно получить с помощью команды терминала startlxde. После открытия графического интерфейса в правой части панели ОС появится значок сетевых подключений. При нажатии на нее откроется меню доступных беспроводных сетей в соответствии со следующим рисунком. При нажатии на любой из элементов откроется окно, в котором можно ввести пароль. Если ввести пароль для сети с SSID «TEData_864A» и ввести команду «ifconfig», результат будет идентичен показанному на предыдущем рисунке.

На данный момент у нас есть и ПК, и RPi, подключенные к коммутатору по беспроводной сети. Текущая сеть показана на следующем рисунке. Теперь мы можем удалить соединение Ethernet и просто использовать беспроводное соединение между RPi и коммутатором.

2. Подключение USB-камеры к RPi

RPi имеет собственный модуль камеры, который можно использовать. Вместо того, чтобы покупать этот модуль, который может быть дорогостоящим для многих, мы можем просто использовать USB-камеру, которая может быть доступна повсюду по меньшей цене. Конфигурация такой камеры очень проста. Просто подключите USB-камеру к одному из USB-портов RPi. После этого мы можем проверить, хорошо ли работает камера, сделав снимок с помощью пакета «fswebcam». Сначала нам нужно установить этот пакет, используя следующую команду:

pi@raspberry:~ $ sudo apt-get install fswebcam

После этого мы можем использовать его для захвата изображения. Самый простой способ сделать это:

pi@raspberry:~ $ sudo fswebcam test_image.jpg

Это получает доступ к камере, захватывает изображение и сохраняет его на SD-карту в текущем каталоге с именем «test_image.jpg». Результат после выполнения команды показан на следующем рисунке.

Вот захваченное изображение:

3. Захват изображений с помощью PyGame

Пакет «fswebcam» полезен для быстрой проверки исправности камеры. Убедившись, что он работает нормально, мы можем приступить к созданию скрипта Python, который обращается к камере для непрерывного захвата изображений с использованием библиотеки PyGame. Следующий код использует PyGame для захвата одного изображения, открывает окно для отображения этого изображения и, наконец, сохраняет такое изображение.

import pygame
 import pygame.camera
 
 # Captured image dimensions. It should be less than or equal to the maximum dimensions acceptable by the camera.
 width = 320
 height = 240
 
 # Initializing PyGame and the camera.
 pygame.init()
 pygame.camera.init()
 
 # Specifying the camera to be used for capturing images. If there is a single camera, then it have the index 0.
 cam = pygame.camera.Camera("/dev/video0",(width,height))
 
 # Preparing a resizable window of the specified size for displaying the captured images.
 window = pygame.display.set_mode((width,height),pygame.RESIZABLE)
 
 # Starting the camera for capturing images.
 cam.start()
 
 # Capturing an image.
 image = cam.get_image()
 
 # Stopping the camera.
 cam.stop()
 
 # Displaying the image on the window starting from the top-left corner.
 window.blit(image,(0,0))
 
 # Refreshing the window.
 pygame.display.update()
 
 # Saving the captured image.
 pygame.image.save(window,'PyGame_image.jpg')

Предположим, что приведенный выше код сохранен в файле Python с именем «im_cap.py». Чтобы выполнить такой код, мы можем выполнить следующую команду из терминала:

pi@raspberry:~ $ python3 im_cam.py

Вот окно, отображаемое после выполнения такого файла.

Мы можем изменить предыдущий код, чтобы захватить более одного изображения. Например, мы можем использовать цикл for для захвата ряда ранее указанных изображений. Мы также можем использовать цикл while, который не ограничен количеством изображений. Вот модифицированный код, который захватывает 2000 изображений с помощью цикла for.

import pygame

import pygame.camera



# Captured image dimensions. It should be less than or equal to the maximum dimensions acceptable by the camera.

width = 320

height = 240



# Initializing PyGame and the camera.

pygame.init()

pygame.camera.init()



# Specifying the camera to be used for capturing images. If there is a single camera, then it has the index 0.

cam = pygame.camera.Camera("/dev/video0", (width, height))



# Preparing a resizable window of the specified size for displaying the captured images.

window = pygame.display.set_mode((width, height), pygame.RESIZABLE)



# Starting the camera for capturing images.

cam.start()



for im_num in range(0, 2000):

    print("Image : ", im_num)



    # Capturing an image.

    image = cam.get_image()



    # Displaying the image on the window starting from the top-left corner.

    window.blit(image, (0, 0))



    # Refreshing the window.

    pygame.display.update()



    # Saving the captured image.

    pygame.image.save(window, './pygame_images/image_' + str(im_num) + '.jpg')



# Stopping the camera.

cam.stop()

Вот 8 отснятых изображений. Обратите внимание, что положение камеры немного изменилось.

4. Построение фоновой модели.

До этого момента мы успешно создали простую систему наблюдения, в которой камера фиксирует изображения, которые сохраняются на SD-карте RPi. Мы можем расширить это, чтобы автоматически обнаруживать изменения в сцене. Это делается путем создания фоновой модели сцены. Любое изменение такой модели будет означать изменение. Например, если кто-то проходит через сцену, фон изменится.

Модель фона может быть просто создана путем усреднения нескольких захваченных изображений на фоне сцены без каких-либо объектов в них. Поскольку нас интересует информация о цвете, изображения будут преобразованы в двоичные. Вот код Python, используемый для построения фоновой модели.

import skimage.io

import os

import numpy



dir_files = os.listdir('./pygame_images/')
bg_image = skimage.io.imread(fname=dir_files[0], as_grey=True)



for k in range(1, len(dir_files)):

    fname = dir_files[k]

    im = skimage.io.imread(fname=fname, as_grey=True)

    bg_image = bg_image + im



bg_image = bg_image/(len(dir_files))

bg_image_bin = bg_image > 0.5



skimage.io.imsave(fname='bg_model.jpg', arr=bg_image)

skimage.io.imsave(fname='bg_model_bin.jpg', arr=bg_image_bin*255)

Вот модель фона в сером и двоичном вариантах после усреднения 500 изображений.

5. Обнаружение изменений в фоновой модели

После построения модели фона мы можем протестировать новое изображение, чтобы проверить, есть ли изменение фона. Это делается просто путем преобразования нового изображения в двоичное. Затем количество белых пикселей сравнивается на обоих изображениях. Если число превышает заданный порог, это указывает на изменение фона. Порог меняется от сцены к сцене. Вот код, используемый для тестирования нового изображения.

bg_num_ones = numpy.sum(bg_image_bin)
test = skimage.io.imread(fname="./pygame_images/image_800.jpg", 

                         as_grey=True)

test_bin = test > 0.5

test_num_ones = numpy.sum(test_bin)

print("Num 1s in BG   :", bg_num_ones)

print("Num 1s in Test :", test_num_ones)

if(abs(test_num_ones-bg_num_ones) < 5000):

    print("Change.")

Вот тестовое изображение в цвете, сером и двоичном, в котором есть изменение фона из-за появления объекта (человека) в сцене.

6. Построение простой схемы, которая зажигает светодиод, когда происходит изменение.

В качестве индикатора изменения фоновой модели мы можем построить простую схему, в которой светодиод загорается, когда происходит изменение. Эта схема будет подключена к бинам GPIO (универсальный ввод-вывод) RPi. Схема нуждается в следующих компонентах:

  • Один макет.
  • Один привел.
  • Один резистор (более или равный 100 Ом). Я использую резистор на 178,8 Ом.
  • Две перемычки папа / папа.
  • Две перемычки папа / мама.

Рекомендуется протестировать схему перед подключением ее к контактам GPIO. Это связано с тем, что, если значение резистора было выбрано неправильно, это может привести не только к сгоранию светодиода, но и к повреждению контактов GPIO. Для проведения теста нам понадобится аккумулятор для питания макета. Вот схема после правильного подключения всех компонентов.

После этого мы можем извлечь аккумулятор и подключить макет к контактам GPIO RPi. Исходя из нумерации контактов GPIO на макетной плате, земля подключается к клемме № 20, а высокое напряжение подключается к выходной клемме 22. На следующем рисунке показаны соединения между макетной платой и RPi. RPi также подключается как к зарядному устройству, так и к USB-камере.

Выходной бункер GPIO управляется с помощью скрипта Python, приведенного ниже. Его состояние по умолчанию - НИЗКИЙ, что означает, что светодиод выключен. При изменении фона состояние будет изменено на ВЫСОКИЙ, что означает, что светодиод включен. Светодиод остается включенным в течение 0,1 секунды, затем его состояние снова не горит. Когда другое входное изображение отличается от фона, светодиод снова включается еще на 0,1 секунды.

import time
 import RPi.GPIO
 import skimage.io
 import numpy
 import os
 import pygame.camera
 import pygame
 
 #####GPIO#####
 # Initializing the GPIO pins. The numbering using is board.
 RPi.GPIO.setmode(RPi.GPIO.BOARD)
 
 # Configuring the GPIO bin number 22 to be an output bin.
 RPi.GPIO.setup(22, RPi.GPIO.OUT)
 
 #####PyGame#####
 # Initializing PyGame and the camera.
 pygame.init()
 pygame.camera.init()
 
 # Captured image dimensions. It should be less than or equal to the maximum dimensions acceptable by the camera.
 width = 320
 height = 240
 
 # Preparing a resizable window of the specified size for displaying the captured images.
 window = pygame.display.set_mode((width, height), pygame.RESIZABLE)
 
 # Specifying the camera source and the image dimensions.
 cam = pygame.camera.Camera("/dev/video0",(width,height))
 cam.start()
 
 #####Background Model#####
 # Reading the background model.
 bg_image = skimage.io.imread(fname='bg_model_bin.jpg', as_grey=True)
 bg_image_bin = bg_image > 0.5
 bg_num_ones = numpy.sum(bg_image_bin)
 
 im_dir = '/home/pi/pygame_images/'
 
 for im_num in range(0, 2000):
     print("Image : ", im_num)
 
     im = cam.get_image()
 
     # Displaying the image on the window starting from the top-left corner.
     window.blit(im, (0, 0))
 
     # Refreshing the window.
     pygame.display.update()
 
     pygame.image.save(window, im_dir+'image'+str(im_num)+'.jpg')
     im = pygame.surfarray.array3d(window)
 
     test_bin = im > 0.5
     test_num_ones = numpy.sum(test_bin)
 
     # Checking if there is a change in the test image.
     if (abs(test_num_ones - bg_num_ones) < 5000):
         print("Change.")
         try:
             RPi.GPIO.output(22, RPi.GPIO.HIGH)
             time.sleep(0.1)
             RPi.GPIO.output(22, RPi.GPIO.LOW)
         except KeyboardInterrupt:  # CTRL+C
             print("Keyboard Interrupt.")
         except:
             print("Error occurred.")
 
 # Stopping the camera.
 cam.stop()
 
 # cleanup all GPIO pins.
 print("Clean Up GPIO.")
 RPi.GPIO.cleanup()

На следующем рисунке показано одно входное изображение, которое отличается от фонового изображения из-за наличия человека. В результате светодиод загорится на 0,1 секунды.

На следующем видео (https://youtu.be/WOUG-vjg3A4) показано состояние светодиода для нескольких кадров, снятых с помощью камеры. Светодиод включается, когда входное изображение отличается от фоновой модели в соответствии с используемым порогом.

Больше подробностей

Ахмед Фаузи Гад, Создание классификатора изображений, работающего на Raspberry Pi, сентябрь 2018 г. https://www.linkedin.com/pulse/building-image-classifier-running-raspberry-pi- ахмед-гад

Для связи с автором