Здравствуйте, я школьник 11 классов, интересуюсь программированием, около-IT тематикой.

Пишу данный пост с целью поделиться своим проектом, занявшим 10 часов моей жизни на выходных и выполненным с целью понять возможности современных методов анализа данных. Публикация может рассматриваться как пример удачной реализации для людей, несведущих в этой области знания, а также как просьба указать мои ошибки для людей, соответственно, сведущих.

Дано: видео-поток с камеры видеонаблюдения, на котором имеется фрагмент 100x50 пикселей с изображением конкретно парковочного места, на котором может присутствовать или отсутствовать лишь конкретный автомобиль.

Изображение с камеры

Изображение парковочного места


Задача: определить наличие или отсутствие автомобиля на парковочном месте.

Получение изображения с камеры


Я использую библиотеку openCV для получения и предобработки изображения.
Следующий код я использовал для построения датасета, который использую для обучения нейросети: я фотографирую ежечасно парковочное место, и после получения 60 фотографий вручную разделяю их на фото с машиной и без неё.

dataminer.py
import cv2 as cv
import numpy as np
import time

cap = cv.VideoCapture()
r = 0
while r <=100:
    cap.open('http://**.**.***.***:***/*****CG?container=mjpeg&stream=main') #URL-адрес видеопотока
    hasFrame, frame = cap.read()#Чтение кадра из потока
    frame = frame[100:200, 300:750]
    box = [0,335,100,385] 
    quantframe = frame[box[0]:box[2], box[1]:box[3]]#Сохранение в отдельную переменную части кадра с изображением машины
    r+=1
    cv.imwrite(str(r)+'.png',quantframe) #Сохранение изображения машины в файл
    print('saved')
    cap.release()
    time.sleep(3600)
    key = cv.waitKey(1)
    if key & 0xFF == ord('q'):
        cv.destroyAllWindows()
        break


Обработка изображения


Я посчитал верным решением обучать нейросеть не на исходных изображениях, а на изображениях с контурами автомобиля, найденными посредством функции cv2.findcontours(...).

Вот код, преобразующий исходное изображение в изображение контуров:

Нахождение контуров
def contoursfinder(image):
  img = image.copy()
  srcimg = img.copy()
  hsv_min = np.array((0, 0, 0), np.uint8)
  hsv_max = np.array((255, 255, 60), np.uint8) #Поскольку контуры находятся по различиям в цвете между частями картинки, необходимо подобрать параметры, исходя из цветовой гаммы картинки
  hsv = cv.cvtColor( img, cv.COLOR_BGR2HSV )
  thresh = cv.inRange( hsv, hsv_min, hsv_max )
  contours, _  = cv.findContours(thresh, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
  img = np.zeros((100,50,3), np.uint8)
  cv.drawContours(img, contours, -1, (255,255,255), 1, cv.LINE_AA)
  return cv.cvtColor(img, cv.COLOR_BGR2GRAY)


Результат работы функции:

Скрытый текст

Нейронная сеть


Я использовал библиотеку tensorflow(keras).

Архитектура сети списана с примера с интернетов: для меня неочевидно объяснение, почему именно так. Если знающие люди расскажут или подскажут где почитать, почему эта архитектура эффективна или почему какая-та другая будет эффективнее, буду безмерно благодарен.
Модель нейросети: последовательна, состоит из двух плотных скрытых слоев в 256 и 128 нейронов и входного, выходного слоев.

Код
model = keras.Sequential([
    keras.layers.Flatten(input_shape=(100, 50)),
    keras.layers.Dense(256, activation=tf.nn.relu),
    keras.layers.Dense(128, activation=tf.nn.relu),
    keras.layers.Dense(2, activation=tf.nn.softmax)
])
model.compile(optimizer=tf.train.AdamOptimizer(), 
              loss='sparse_categorical_crossentropy',
              metrics=['accuracy'])
model.fit(trainingimagesarr, trainingimagesarrlabel, epochs=1, callbacks=[tbCallBack])


Перед обучением вся numpy матрица была поделена на 255, дабы давать на вход нейросети числа в диапазоне от 0 до 1.

trainingimagesarr = trainingimagesarr / 255.0
trainingimagesarrlabel = np.array(trainingimagesarrlabel)-1

Теперь я могу вызвав функцию:

def realtest():
  cap = cv.VideoCapture()
  cap.open('http://**.**.***.***:***/*****CG?container=mjpeg&stream=main')
  hasFrame, frame = cap.read()
  frame = frame[100:200, 300:750]
  quantframe = frame[0:100,275:325]
  quantframe = contoursfinder(quantframe)
  return model.predict(np.array([quantframe]))[0][1]>0.60

получить данные о наличии автомобиля на стоянке.

Сильно не пинайте, но чуть-чуть :-)

Спасибо!

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


  1. sshikov
    17.02.2019 18:52
    +5

    Я мало что понимаю в нейронных сетях, чтобы критиковать само решение. Но мне кажется, что свою домашнюю работу вы не доделали. Ну вот смотрите:

    >Я посчитал верным решением обучать нейросеть не на исходных изображениях, а на изображениях с контурами автомобиля, найденными посредством функции cv2.findcontours(...).

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

    Ну или вот тут:

    >Архитектура сети списана с примера с интернетов: для меня неочевидно объяснение, почему именно так.

    Опять же, домашняя работа не завершена. Нормальный вариант выглядел бы так: архитектура взята вот тут (ссылка), там она применяется для решения похожей задачи (почему вы или автор архитектуры считаете, что они похожи), с хорошими результатами. А так вообще непонятно, что за архитектуру вы взяли, и почему именно ее?

    Ну и кстати, ваши-то результаты где? Каково качество, быстродействие, какие-то еще показатели? Оно вообще работает?


    1. bibiw_one Автор
      18.02.2019 23:16

      Спасибо за комментарий

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

      Мой интерес состоит в том числе и в том, насколько просто использовать простые структуры: в нейросети сравнительно мало нейронов(этим объясняется высокое быстродействие), однако она работает с 80% точностью(для кадров разнесенных во времени). Работает это только потому, что я анализирую не сами изображения, а найденные алгоритмом контуры

      Подобный подход к решению задачи классификации изображений(персептрон) я увидел в примере из документации tensorflow(они классифицировали MNIST датасет, черно-белые картинки 25х25 пикселей с изображениями разных видов одежды).


  1. unwrecker
    18.02.2019 10:13

    А цель проекта какая? Можно сделать полезное приложение, если находить свободные места на парковке.


  1. mehos
    18.02.2019 13:52

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


    1. bibiw_one Автор
      18.02.2019 23:00

      У меня задача попроще: парковочное место — личное, машина ставится всегда одинаково, и никто кроме одной машины там не появляется
      Вероятно, можно было бы справиться и без нейросети, но целью и лейтмотивом затеи являлось изучение, пусть и поверхностное, возможностей данного метода


  1. rdnve
    18.02.2019 22:50
    +1

    Разработчик из Калифорнии делал подобное.


  1. arizhiy
    18.02.2019 22:50
    +1

    > Если знающие люди расскажут или подскажут где почитать, почему эта архитектура эффективна или почему какая-та другая будет эффективнее, буду безмерно благодарен.
    Для распознавания изображений лучше использовать свертчные сети (почитай как они работают например VGG, ResNet и тд)
    Но вобще непонятные твои результаты, есть ли что улучшать или нет


    1. bibiw_one Автор
      18.02.2019 22:53

      Спасибо, почитаю