№ 8212 В разделе
Programming
от November 5th, 2016,
В подшивках: Computer Vision, Python
У нас по городу висят камеры на некоторых ключевых перекрестках и ж\д переездах. Например, переезд на улице Мокрушина. Но это не всегда удобно, т.к. перед выездом приходится смотреть на камеры. Поскольку я модный авторадиоклубень и даже немного программист было принято решение написать программу, которая постит в наш клубный телеграм уведомление когда открываются или закрываются переезды.
Первое, что необходимо сделать – обучить нейронную сеть данными. В моем случае это состояние светофора. Процесс трудоемкий и не всегда эффективный, но если удалось обучить хорошо, то вероятность ошибок заметно снижается.
Итак, я выкачиваю видеопоток длительностью буквально несколько секунд. Этого хватит и на обучение, и на распознавание. Анализировать всю картинку нифига не хорошо. Нужно из нее вырезать только часть и анализировать ее. Я средствами ffmpeg сначала вырезаю нужный мне кусочек из видеофайла размером 28х16 пикселов, а затем потрошу это маленькое видео на отдельные кадры. На картинке внизу наглядно показаны сэмплы, которыми я обучал нейросеть. Захват необходимо делать в разное время суток, т.к. освещение постоянно меняется. Вечером это может быть натриевые лампы, дающие дополнительную красноту, а днем яркость вообще снижается и светофор может быть не виден.
Лепим простейший скрипт, который выкачивает видеофайл, вырезает нужный из него прямоугольник и разрезает на отдельные кадры. Назовем его grab.sh и в параметре ему будем передавать 0 или 1 (нет поезда, есть поезд). Ничего сложного:
#!/bin/bash
HM=$(date +"%H_%M")
echo $HM
stream=$(curl -s http://cdn08.vtomske.ru/hls/stream6.m3u8|grep stream|head -n 1)
echo $stream
curl -s http://cdn08.vtomske.ru/hls/$stream > temp.ts
ffmpeg -loglevel panic -i "temp.ts" -filter:v "crop=28:16:1099:491" "temp_cropped.mp4"
ffmpeg -loglevel panic -i "temp_cropped.mp4" -vf fps=1 "$1/$HM-%d.png"
rm temp.ts temp_cropped.mp4
Итак, сэмплы вырезаны и разложены по каталогам. Теперь необходимо провести обучение сети. Я использовал библиотеки PIL и pyfann. Поскольку я обрабатываю картинки размером 28х16 пикселов у меня получается 448 нейронов, 3 слоя и 1 выходное значение 0 или 1. Я использую только красный канал от картинки. Создаем файл learn.py:
from pyfann import libfann
from PIL import Image
import os
У меня есть 3 массива, куда я помещаю данные для обучения:
datastruct = []
files=[]
learn=[]
files хранит имена файлов, datastruct хранит в себе яркость красного для каждой картинки, а в learn готовые ответы 0 или 1.
Файлы для обучения раскиданы по 2 директориям по аналогии “есть поезд”, “нет поезда”. Делаем поиск по директориям и помещаем найденное в массив:
for filename in os.listdir("0"):
if filename.endswith(".png"):
files.append("0/"+filename)
learn.append([0])
for filename in os.listdir("1"):
if filename.endswith(".png"):
files.append("1/"+filename)
learn.append([1])
Подготовка закончена. Самое время собрать данные в память:
for filename in files:
im = Image.open(filename, 'r')
pixel_values = list(im.getdata(0))
datastruct.append(pixel_values)
Данные подготовлены и теперь можно приступать к обучению. Создаем объект сети, создаем объет с данными, нейросеть колбасит все это и затем сохраняем в файл:
desired_error = 0.001
max_epochs = 1000
epochs_between_reports = 1000
ann = libfann.neural_net()
ann.create_standard_array((448,150,1))
ann.set_activation_function_hidden(libfann.SIGMOID_SYMMETRIC_STEPWISE)
ann.set_activation_function_output(libfann.SIGMOID_SYMMETRIC_STEPWISE)
train_data = libfann.training_data()
train_data.set_train_data(datastruct, learn)
ann.train_on_data(train_data,max_epochs, epochs_between_reports, desired_error)
ann.save('fann.data')
ann.destroy()
Ура! Ура! Ура! Файл обучения сохранен и теперь можно приступать к распознаванию.
Делаем скрипт, который выкачает видеофайл, порежет и разберет на картинки:
#!/bin/bash
stream=$(curl -s http://cdn08.vtomske.ru/hls/stream6.m3u8|grep stream|head -n 1)
echo $stream
curl -s http://cdn08.vtomske.ru/hls/$stream > temp.ts
ffmpeg -loglevel panic -i "temp.ts" -filter:v "crop=28:16:1099:491" "temp_cropped.mp4"
ffmpeg -loglevel panic -i "temp_cropped.mp4" -vf fps=1 "detect_images/%d.png"
python detect.py
rm temp.ts temp_cropped.mp4 detect_images/*
Ничего сложного. Теперь делаем непосредственно скрипт detect.py:
from pyfann import libfann
from PIL import Image
ann = libfann.neural_net()
ann.create_from_file('fann.data')
imdir="detect_images"
files = ["1.png"]
im = Image.open(imdir+"/"+files[0], 'r')
pix = list(im.getdata(0))
res = ann.run(pix)
print res
if res[0]>0.7:
print "Train!"
else:
print "Road clear"
И все! Можно пробовать уже что-нибудь определить. Утренний тест (серое время суток):
root@dev:/opt/detector# ./check.sh stream6-36738.ts [1.0] Train! root@dev:/opt/detector# ./check.sh stream6-36740.ts [1.0] Train! root@dev:/opt/detector# ./check.sh stream6-36811.ts [0.3132553062939588] Road clear root@dev:/opt/detector# ./check.sh stream6-37074.ts [0.27650208828934875] Road clear
Ночной тест
По результатам видим, что поезд проехал, а потом переезд открылся. Все определено верно.
Скачать готовый код можно в моем репозитории: https://git.blindage.org/21h/pyfann-train-detector
Документации вменяемой для pyfann все еще нет. Вот вам полезная ссылка http://blog.psibi.in/2012/04/using-fann-to-create-networks-properly.html
Fortune cookie: Sniff sniff... Hey! Who farted?
А зачем нейросеть? Почему цвет светофора определить без нейросетей?
потому, что нейросетью проще. яркость светофора меняется в зависимости от времени суток от маленькой красной точки до жирной белой точки с красной окантовкой. как ты это определять будешь без нейросети даже представить сложно.