Изменения

Перейти к: навигация, поиск

Оценка положения

39 373 байта убрано, 19:53, 28 ноября 2020
Нет описания правки
{{В разработке}}
{{Определение|definition ='''Оценка положения''' (англ. ''Pose Estimation'') {{-- представляет собой сочетание аппаратных средств -}} задача определения структуры объекта и программного обеспечения, которое позволяет определить абсолютное положение объекта положения этой структуры в пространстве. }}
== Области применения ==
Задача оценки положения движущихся и статичных объектов возникает во множестве прикладных областей. Сейчас происходит подъем популярности разработки устройств и систем, отслеживающих положения объектов окружающего мира и использующих эту информацию для различных целей, рассмотрим . Рассмотрим несколько областей:
#'''Транспортные средства с встроенными системами помощи водителю ''' ''(автопилот, круиз контроль и др.)''. Которые Эти системы помогают водителю с парковкой, контролируют скорость и направление движения, а также предупреждают об объектах, находящихся на дороге, о типе дорожного покрытия и возможных авариях.#'''Дополненная реальность:''' устройства , в которых в реальное изображение, получаемое с помощью видеокамер, встраивается некоторая информация , полезная человеку.#'''Виртуальная реальность: ''' оценка положения, как технология , является критически важной для достижения эффекта погружения в виртуальную реальность. В сочетании с отслеживанием ориентации становится возможным измерять и передавать в ВР виртуальную реальность все 6 степеней свободы ([https://en.wikipedia.org/wiki/Six_degrees_of_freedom 6-DoF]) реального мира.#'''Робототехника: '''Роботы роботы (Медицинскиемедицинские, научные, промышленные и др.) , которые основывают свое движение на построении карты окружения и препятствий.#'''Веб-технологии: '''Исследование юзабилити и исследование пользовательского опытаи удобства использования продукта.
== Методы решения задачи оценки положения ==
=== Акустические методы===
Акустические приборы слежения используют ультразвуковые (высокочастотные) звуковые волны для измерения положения и ориентации целевого объектав пространстве. Для определения положения объекта либо измеряется время пролёта ([https://en.wikipedia.org/wiki/Time_of_arrival time-of-arrival]) звуковой волны от передатчика к приёмникам, либо разность фаз синусоидальной звуковой волны при приёмо-передаче. Алгоритмы трекинга отслеживания положения при использовании акустических приборов основаны на [https://en.wikipedia.org/wiki/True_range_multilateration Трилатерациитрилатерации] и расчете [https://en.wikipedia.org/wiki/Angle_of_arrival Угла Прибытияугла прибытия].При использовании данных методов, разработчики сталкиваются с некоторыми проблемами: акустические трекеры, как правило имею , имеют низкую скорость обновления , связанную с низкой скорости скоростью звука в воздухе, скорость звука в воздухе которая зависит от внешних факторов среды, таких как температура, давление и влажность.
=== Радиочастотные методы ===
Методов, основанных на радиочастотах , достаточно много.#'''Позиционирования Позиционированиe с использованием пассивных радиочастотных идентификаторов [https://ru.wikipedia.org/wiki/RFID#Антиколлизионный_механизм_(меток) RFID]''' <br /> Основное назначение систем с пассивными RFID метками {{---}} идентификация. Они применяются в системах, традиционно использовавших штрих-коды или магнитные карточки : в системах распознавания товаров и грузов, опознания людей, в системах контроля и управления доступом (СКУД) и т.п.Система включает RFID метки с уникальными кодами и считыватели и работает следующим образом. Считыватель непрерывно генерирует радиоизлучение заданной частоты. ЧИП метки, попадая в зону действия считывателя, использует это излучение в качестве источника электропитания и передает на считыватель идентификационный код. Радиус действия считывателя составляет около метра.<br />#'''Позиционирование с использованием активных [https://ru.wikipedia.org/wiki/RFID#Антиколлизионный_механизм_(меток) RFID] ''' <br/>Активные радиочастотные метки используются при необходимости отслеживания предметов на относительно больших расстояниях (например, на территории сортировочной площадки). Рабочие частоты активных RFID меток {{---}} 455МГц, 2,.4ГГц или 5,.8ГГц, а радиус действия {{---}} до ста метров. Питаются активные метки от встроенного аккумулятора.Существуют активные метки двух типов: [https://ru.wikipedia.org/wiki/Маркерный_радиомаяк радиомаякиТранспондер транспондеры] и [https://ru.wikipedia.org/wiki/Транспондер транспондерыМаркерный_радиомаяк радиомаяки]. Транспондеры включаются, получая сигнал считывателя. Они применяются в АС оплаты проезда, на КПП, въездных порталах и других подобных системах.Радиомаяки используются в системах позиционирования реального времени. Радиомаяк отправляет пакеты с уникальным идентификационным кодом по команде либо с заданной периодичностью. Пакеты принимаются как минимум тремя приемниками, расположенными по периметру контролируемой зоны. Расстояние от маячка до приемников с фиксированными координатами определяются по углу направления на маячок [https://en.wikipedia.org/wiki/Angle_of_arrival Angle of arrival] (AoA), по времени прихода сигнала [https://en.wikipedia.org/wiki/Time_of_arrival Time of arrival] (ToA) или по времени распространения сигнала от маячка до приемника [https://en.wikipedia.org/wiki/Time_of_flight Time-of-flight] (ToF).Инфраструктура системы строится на базе проводной сети и в двух последних случаях требует синхронизации.<br />#''' Ultra Wideband (UWB) позиционирование '''<br/> Технология UWB (сверхширокополосная) использует короткие импульсы с максимальной полосой пропускания при минимальной центральной частоте. У большинства производителей центральная частота составляет несколько гигагерц, а относительная ширина полосы {{---}} 25-100%. Технология используется в связи, радиолокации, измерении расстояний и позиционировании.Это обеспечивается передачей коротких импульсов, широкополосных по своей природе. Идеальный импульс (волна конечной амплитуды и бесконечно малой длительности), как показывает [https://ru.wikipedia.org/wiki/Анализ_Фурье анализ Фурье], обеспечивает бесконечную полосу пропускания. UWB сигнал не походит на модулированные синусоидальные волны, а напоминает серию импульсов. Производители предлагают разные варианты UWB технологии. Различаются формы импульсов. В некоторых случаях используются относительно мощные одиночные импульсы, в других {{---}} сотни миллионов маломощных импульсов в секунду. Применяется как когерентная (последовательная) обработка сигнала, так и не когерентная. Все это приводит к значительному различию характеристик UWB систем разных производителей.
=== Магнитные методы ===
Магнитный трекинг основан Магнитные методы основаны на измерении интенсивности магнитного поля в различных направлениях. Как правило, в таких системах есть [https://ru.wikipedia.org/wiki/Базовая_станция базовая станция], которая генерирует переменный или постоянный ток. Так как сила магнитного поля уменьшается с увеличением расстояния между точкой измерения и базовой станциистанцией, можно определить местоположение контроллера, зная силу магнитного поля. Если точка измерения вращается, то распределение магнитного поля изменяется по различным осям, что позволяет определить ориентацию. Наиболее известными продуктами на основе магнитного трекинга являются [https://ru.wikipedia.org/wiki/Виртуальная_реальность VR] контроллер [https://ru.wikipedia.org/wiki/Hydra_(контроллер) Razer Hydra] и система [https://www.sixense.com/platform/hardware/ STEM] от компании Sixense. Точность данного метода может быть достаточна высока в контролируемых условиях (в спецификациях Hydra говорится о 1 мм позиционной точности и 1 градусе точности ориентации), однако магнитное отслеживание подвержено помехам от токопроводящих материалов вблизи излучателя или датчика, от магнитных полей, создаваемых другими электронными устройствами и ферромагнитных материалов в пространстве отслеживания.
=== Оптические методы ===
Оптические методы представляют собой совокупность алгоритмов [https://ru.wikipedia.org/wiki/Компьютерное_зрение компьютерного зрения] и отслеживающих устройств, в роли которых выступают камеры видимого или инфракрасного диапазона, стерео-камеры и камеры глубины. Оптический трекинг основан на том же принципе, что и стереоскопического стереоскопическое зрения человека. Когда человек смотрит на объект с помощью бинокулярного зрения, он в состоянии определить , приблизительно на каком расстоянии объект находится. Не достаточно просто установить пару несколько камер для имитации стереоскопического зрения человека. Камеры должны определить расстояние до объекта и его положения в пространстве, так что их необходимо откалибровать.[https://ru.wikipedia.org/wiki/Оптическая_система Оптические системы] надежны и относительно дешевы, но их с ними трудно калиброватьпровести начальную калибровку. Кроме того, система требует прямой линии света без закупорки, в противном случае мы получаем неправильные данные.
В зависимости от наличия специальных оптических маркеров выделяют отдельно:
*'''Без маркерный Безмаркерный трекинг: '''как правило строится на сложных алгоритмах с использованием двух и более камер, либо стерео -камер с сенсорами глубины. Используется наибольшим образом в автомобилях с автопилотам автопилотом и иными системами помощи водителю.
*'''Трекинг с использованием маркеров:''' предполагает заранее заданную модель объекта, которую можно отслеживать даже с одной камерой. Маркерами обычно служат источники инфракрасного излучения (как активные, так и пассивные), а также видимые маркеры наподобие [https://ru.wikipedia.org/wiki/QR-код QR]-кодов. Такой вид трекинга возможен только в пределах прямой видимости маркера.
[[Файл:Pnp.gif |400px|thumb| right| Рис. 1 Задача (PnP)]]
При оптическом отслеживании для определения положения объекта в пространстве решается так называемая задача PnP (Perspective-n-Point),когда по перспективной проекции объекта на плоскость сенсора камеры необходимо определить положение объекта в 3D-пространстве.
Для заданной 3D-модели объекта и 2D-проекции объекта на плоскость камеры решается система уравнений. В результате чего получается множество возможных решений. Количество решений зависит от числа точек в 3D-модели объекта.\ Однозначное решение для определения 6-DoF положения объекта можно получить как минимум при 4 точках. Для треугольника получается от 2 до 4 возможных решений, то есть положение не может быть определено однозначно. [[Файл:triangles.gif |400px|thumb| right| Рис. 2 Решение "треугольников"]]
Решение предлагается достаточно большим количеством алгоритмов, реализованных в виде библиотек:
#'''[http://sv-journal.org/2015-4/09/index.php?lang=ru POS]''' ''(Pose from Orthography and Scaling)'', аппроксимирующий перспективную проекцию с помощью масштабированной ортогональной проекции и находящий матрицу поворота и вектор сдвига объекта путём решения линейной системы уравнений.
#'''[https://github.com/opencv/opencv/wiki/Posit POSIT]''' ''(POS with ITerations)'', который использует в цикле аппроксимацию нахождения положения POS для нахождения более хорошей масштабированной ортогональной проекции особых точек, а затем применяет POS к этим точкам, а не к исходным. POSIT сходится к точному решению за несколько итераций.
#'''[https://opencv.org/ OpenCV]''' {{---}} библиотека компьютерного зрения широкого назначения с открытым исходным кодом. Основные части библиотеки {{---}} интерпретация изображений и алгоритмы машинного обучения. Список возможностей, предоставляемых OpenCV, весьма обширен: интерпретация изображений, калибровка камеры по эталону, устранение оптических искажений, анализ перемещения объекта, определение формы объекта и слежение за объектом, сегментация объекта и др. Нам же интереcтно интереcен метод [https://docs.opencv.org/3.1.0/d9/d0c/group__calib3d.html#ga549c2075fac14829ff4a58bc931c033d solvePnP].
=== SLAM {{---}} Simultaneous Localization and Mapping === Метод одновременной локализации и построения карты (SLAM) {{---}} наиболее популярный способ позиционирования, который применяется для отслеживания положения в пространстве.[[Файл:Slam.png |400px|thumb| right| Рис. 3 Метод SLAM]]Алгоритм состоит из двух частей: первая {{---}} составление карты неизвестного окружающего пространства на основе измерений (данные с [https://ru.wikipedia.org/wiki/Одометр одометра] или [https://ru.wikipedia.org/wiki/Стереоскопический_фотоаппарат стерео-камеры]), вторая {{---}} определение своего местоположения (локализация) в пространстве на основе сравнения текущих измерений с имеющейся картой пространства. Данный цикл непрерывно пере вычисляетсяперевычисляется, при этом результаты одного процесса участвуют в вычислениях другого процесса. Наиболее популярные методы решения задачи включают в себя фильтр частиц и расширенный [https://ru.wikipedia.org/wiki/Фильтр_Калмана фильтр Калмана].SLAM удобен для мобильных решений виртуальной и дополненной реальности. Недостатком данного подхода является большая вычислительная сложность.
=== Инерциальный трекинг ===
Современные инерциальные измерительные системы ([https://en.wikipedia.org/wiki/Inertial_measurement_unit IMU]) на основе [https://ru.wikipedia.org/wiki/Микроэлектромеханические_системы MEMS-технологии] позволяют отслеживать ориентацию (roll, pitch, yaw) в пространстве с большой точностью и минимальными задержками.[[Файл:gyro.gif |400px|thumb| right| Рис. 4 MEMS]]
Благодаря алгоритмам [https://en.wikipedia.org/wiki/Sensor_fusion «sensor fusion»] на основе [https://robotclass.ru/articles/complementary-filter комплементарного фильтра] или [https://ru.wikipedia.org/wiki/Фильтр_Калмана фильтра Калмана] данные с гироскопа и акселерометра успешно корректируют друг друга и обеспечивают точность как для кратковременных измерений, так и для длительного периода. Однако определение координат (перемещения) за счёт двойного интегрирования линейного ускорения ([https://en.wikipedia.org/wiki/Dead_reckoning dead reckoning]), вычисленного из сырых данных с [https://ru.wikipedia.org/wiki/Акселерометр акселерометра], не удовлетворяет требованиям по точности на длительных периодах времени. Акселерометр сам по себе даёт сильно зашумленные данные, и при интегрировании ошибка увеличивается со временем квадратично.Решить данную проблему помогает комбинирование инерциального подхода к трекингу с другими методами, которые периодически корректируют, так называемый, дрифт акселерометра.
=== Гибридные методы ===
Так как ни один из методов не является безупречным, и все они имеют свои слабые места, наиболее разумно комбинировать различные методы отслеживания. Так инерциальный трекинг (IMU) может обеспечить высокую частоту обновления данных (до 1000 Гц), в то время как оптические методы могут дать стабильную точность в длительные периоды времени (корректирование дрифта).
== Примеры задач, решаемых с помощью ML ==
=== Обнаружение и обработка дорожных знаков и пешеходов ===
 
====Введение ====
 
'''Обнаружение объектов''' является хорошо известной проблемой в области компьютерного зрения и глубокого обучения. Существует два компонента в модели обнаружения объекта, а именно, базовая нейронная сеть и нейронная сеть обнаружения .
Во-первых, '''базовые нейтральные сети''' -это CNN, которые извлекают объекты из изображения, из объектов низкого уровня, таких как линии, ребра или круги, в объекты более высокого уровня, такие как лицо, человек, светофор или знак стоп и т. д. Несколько хорошо известных базовых нейронных сетей-это LeNet, InceptionNet(он же. GoogleNet), ResNet, VGG-Net, AlexNet, MobileNet и др. Эта [https://medium.com/@RaghavPrabhu/cnn-architectures-lenet-alexnet-vgg-googlenet-and-resnet-7c81c017b848 превосходная статья] обсуждает различия между этими базовыми нейтральными сетями ниже.
 
Затем '''нейронные сети обнаружения''' присоединяются к концу базовой нейронной сети и используются для одновременной идентификации нескольких объектов из одного изображения с помощью извлеченных признаков. Некоторые из популярных сетей обнаружения-SSD (Single Shot MultiBox Detector), R-CNN (регион с функциями CNN), более быстрый R-CNN и YOLO (вы смотрите только один раз) и т. д. В [https://en.wikipedia.org/wiki/Object_detection этой статье] рассматриваются различия между этими нейронными сетями обнаружения.
 
====Modeling training====
 
Выделим несколько этапов связанных с модельным обучением.
#Сбор и маркировка изображений (20-30 мин)
#Выбор модели
#Трансферное обучение / модельное обучение (3-4 часа)
#Сохранить вывод модели в формате Edge TPU (5 мин)
#Запуск вывода модели на Raspberry Pi
 
====Сбор и маркировка изображений====
У нас есть 6 типов объектов, а именно: красный свет, зеленый свет, знак остановки, ограничение скорости 40 миль в час, ограничение скорости 25 миль в час и несколько фигурок Lego в качестве пешеходов.[[Файл:Obj.jpg |400px|thumb| right| Рис. 5 Установленные объекты]] Таким образом, у нас будет около 50 подобных фотографий, с объектами размещенными случайным образом на каждом изображении. Затем пометим каждое изображение с помощью ограничительной рамки для каждого объекта на изображении. С помощью бесплатного инструмента, называемый [https://tzutalin.github.io/labelImg/ labelImg] ''(для Windows / Mac / Linux)'' это можно сделать довольно быстро и просто.
 
 
====Выбор модели====
На Raspberry Pi, так как мы имеем ограниченные вычислительные мощности, мы должны выбрать модель, которая работает относительно быстро и точно. После экспериментов с несколькими моделями, свой выбор остановим на <tt> MobileNet v2 SSD COCO</tt> как на модели с оптимальным балансом между скоростью и точностью.
 
====Трансферное Обучение / Модельное Обучение ====
 
Для этого шага будем использовать Google Colab.
 
Подготовка данных для обучения:
 
repo_dir_path = '/content/DeepPiCar'
% cd{ repo_dir_path} / models/ object_detection
# Convert train folder annotation xml files to a single csv file,
# generate the `label_map.pbtxt` file to `data/` directory as well.
!python code/xml_to_csv.py -i data/ images/ train - o data/ annotations/ train_labels.csv -l data/ annotations
# Convert test folder annotation xml files to a single csv.
!python code/xml_to_csv.py -i data/ images/ test -o data/ annotations/ test_labels.csv
# Generate `train.record`
!python code/generate_tfrecord.py --csv_input=data/annotations/train_labels.csv - - output_path= data/ annotations/ train.record --
img_path=data/images/train --label_map data/annotations/label_map.pbtxt
# Generate `test.record`
!python code/generate_tfrecord.py --csv_input=data/annotations/test_labels.csv - - output_path= data/ annotations/ test.record --
img_path=data/images/test --label_map data/annotations/label_map.pbtxt
 
Приведенный выше код преобразует xml-файлы меток, созданные инструментом LabelImg, в двоичный формат, так что TensorFlow может обрабатывать быстро.
 
Загружаем Pre-trained Model:
 
MODEL_FILE = MODEL + '.tar.gz'
DOWNLOAD_BASE = 'http://download.tensorflow.org/models/object_detection/'
DEST_DIR = '/content/models/research/pretrained_model'
if not( os.path.exists( MODEL_FILE)):
urllib.request.urlretrieve( DOWNLOAD_BASE + MODEL_FILE, MODEL_FILE)
tar = tarfile.open( MODEL_FILE)
tar.extractall()
tar.close()
os.remove( MODEL_FILE)
if(os.path.exists( DEST_DIR)):
shutil.rmtree(DEST_DIR)
os.rename( MODEL, DEST_DIR)
fine_tune_checkpoint = os.path.join( DEST_DIR, "model.ckpt")
print( fine_tune_checkpoint)
 
Приведенный выше код загрузит предварительно обученные файлы модели для <tt>ssd_mobilenet_v2_quantized_300x300_coco_2019_01_03</tt> модель и мы будем только использовать <tt>model.ckpt файл</tt>.
 
Тренируем модель:
 
num_steps = 2000
num_eval_steps = 50
model_dir = '/content/gdrive/My Drive/Colab Notebooks/TransferLearning/Training'
pipeline_file = 'ssd_mobilenet_v2_quantized_300x300_coco.config'
!python /content/models/research/object_detection/model_main.py \
- - pipeline_config_path= { pipeline_fname} \
--model_dir='{model_dir}' \
--alsologtostderr \
--num_train_steps={num_steps} \
--num_eval_steps={num_eval_steps}
 
Этот шаг занимает 3-4 часа, в зависимости от количества шагов, которые вы тренируете ''(они же эпохи или num_steps)''. После того, как тренировка будет завершена, вы увидите кучу файлов в <tt>model_dir</tt>. Мы ищем самое последнее <tt>model.ckpt-xxxx.meta</tt> файл.Во время обучения мы можем отслеживать прогрессирование потерь и точности с помощью '''TensorBoard'''.
 
Тестируем обученную модель: [[Файл:Newobj.jpg |400px|thumb| right| Рис. 6 Опознанные объекты]]
 
После тренировки прогоняем несколько изображений из тестового набора данных через нашу новую модель. Как и ожидалось, практически все объекты на изображении были идентифицированы с относительно высокой достоверностью. Более отдаленные объекты становились больше и легче обнаружить, когда наша машина приближалась к ним.
 
Сохраняем вывод модели в формате Edge TPU:
 
После того, как модель обучена, мы должны экспортировать модель meta файл в диаграмму вывода в формате <tt>Google ProtoBuf</tt>, а затем в формат, который Edge TPU accelerator может понимать и обрабатывать.
 
====Планирование и управление движением====
 
Теперь, когда DeepPiCar может обнаружить и определить, какие объекты находятся перед ним, нам все еще нужно сказать ему, что с ними делать, т. е. управление движением. Существует два подхода к управлению движением, т. е. основанный на правилах и сквозной.<br/>
#'''Подход, основанный на правилах''' значит, нам нужно точно сказать машине, что делать, когда она сталкивается с каждым объектом. Например, скажите автомобилю остановиться, если он видит красный свет или пешехода, или ехать медленнее, если он видит более низкий знак ограничения скорости и т. д. Это сродни тому, что мы сделали в части 4, где мы рассказали автомобилю, как перемещаться по полосе движения с помощью набора кодов/правил.
#'''Сквозной подход''' просто кормит автомобиль большим количеством видеоматериалов хороших водителей, и автомобиль, через глубокое обучение, выясняет сам по себе, что он должен остановиться перед красными огнями и пешеходами или замедлиться, когда ограничение скорости падает.
В статье рассматривается первый подход.
 
Правила довольно просты: если ни один объект не обнаружен, то привод на последнем известном ограничении скорости. Если какой-то объект обнаружен, этот объект изменит скорость автомобиля или ограничение скорости.
 
Во-первых, определяем базовый класс, <tt>TrafficObject</tt>, который представляет собой любые дорожные знаки или пешеходов, которые могут быть обнаружены на дороге. Он содержит метод, <tt>set_car_state(car_state)</tt>. <tt>car_stateСловарь</tt> содержит две переменные, а именно: <tt>speed, и speed_limit</tt>, который будет изменен этим методом. Он также имеет вспомогательный метод, <tt>is_close_by()</tt>, который проверяет, находится ли обнаруженный объект достаточно близко. (Ну, поскольку наша единственная камера не может определить расстояние, приближаем расстояние с высотой объекта. Чтобы точно определить расстояние, нам понадобится лидар или его маленький кузен, ультразвуковой датчик или система камер стереовидения, как в Тесле.)
 
class TrafficObject(object):
def set_car_state( self, car_state):
pass
@staticmethod
def is_close_by( obj, frame_height, min_height_pct= 0,05):
# default: if a sign is 10% of the height of frame
obj_height = obj.bounding_box[ 1] [1] - obj.bounding_box[0][1]
return obj_height / frame_height >> min_height_pct
 
Реализация для красного света и пешехода тривиальны, просто устанавливают скорость автомобиля 0.
 
class RedTrafficLight(TrafficObject):
def set_car_state( self, car_state):
logging.debug('red light: stopping car')
car_state['speed'] = 0
class Pedestrian(TrafficObject):
def set_car_state( self, car_state):
logging.debug('pedestrian: stopping car')
car_state['speed'] = 0
 
Как 25 миль в час, так и 40 миль в час ограничения скорости могут использовать только один класс SpeedLimit, который принимает <tt>speed_limit</tt> в качестве параметра инициализации. Когда знак обнаружен, просто установливаем ограничение скорости автомобиля до соответствующего предела.
 
 
class SpeedLimit( TrafficObject):
def __init__(self, speed_limit):
self.speed_limit = speed_limit
def set_car_state( self, car_state):
logging.debug('speed limit: set limit to %d' % self.speed_limit)
car_state['speed_limit'] = self.speed_limit
Реализация зеленого света еще проще, так как он ничего не делает, но печать зеленого света обнаруживается (код не показан).
 
После того, как мы определили поведение для каждого дорожного знака, нам нужен класс, чтобы связать их вместе, который является <tt>ObjectsOnRoadProcessor</tt> класс. Этот класс сначала загружает обученную модель для Edge TPU, затем обнаруживает объекты в живом видео с моделью и, наконец, вызывает каждый объект трафика для изменения скорости и ограничения скорости автомобиля.
 
class ObjectsOnRoadProcessor(object):
"""
This class 1) detects what objects (namely traffic signs and people) are on the road
and 2) controls the car navigation (speed/steering) accordingly
"""
def __init__(self,
car= None,
speed_limit=40,
model= '/home/pi/DeepPiCar/models/object_detection/data/model_result/road_signs_quantized_edgetpu.tflite',
label= '/home/pi/DeepPiCar/models/object_detection/data/model_result/road_sign_labels.txt',
width= 640,
height= 480):
# model: This MUST be a tflite model that was specifically compiled for Edge TPU.
# https://coral.withgoogle.com/web-compiler/
logging.info('Creating a ObjectsOnRoadProcessor...')
self.width = width
self.height = height
# initialize car
self.car = car
self.speed_limit = speed_limit
self.speed = speed_limit
# initialize TensorFlow models
with open(label, 'r') as f:
pairs = (l.strip().split(maxsplit= 1) for l in f.readlines())
self.labels = dict((int(k), v) for k, v in )
# initial edge TPU engine
logging.info('Initialize Edge TPU with model %s...' % model)
self.engine = edgetpu.detection.engine.DetectionEngine(model)
self.min_confidence = 0.30
self.num_of_objects = 3
logging.info('Initialize Edge TPU with model done.')
self.traffic_objects = {0: GreenTrafficLight(),
1: Person(),
2: RedTrafficLight(),
3: SpeedLimit(25),
4: SpeedLimit(40),
5: StopSign()}
def process_objects_on_road(self, frame):
# Main entry point of the Road Object Handler
objects, final_frame = self.detect_objects(frame)
self.control_car(objects)
return final_frame
def control_car(self, objects):
logging.debug('Control car...')
car_state = {"speed": self.speed_limit, "speed_limit": self.speed_limit}
if len(objects) == 0:
logging.debug('No objects detected, drive at speed limit of %s.' % self.speed_limit)
contain_stop_sign = False
for obj in objects:
obj_label = self.labels[obj.label_id]
processor = self.traffic_objects[obj.label_id]
if processor.is_close_by(obj, self.height):
processor.set_car_state(car_state)
else:
logging.debug("[%s] object detected, but it is too far, ignoring. " % obj_label)
if obj_label == 'Stop':
contain_stop_sign = True
if not contain_stop_sign:
self.traffic_objects[5].clear()
self.resume_driving(car_state)
def resume_driving(self, car_state):
old_speed = self.speed
self.speed_limit = car_state['speed_limit']
self.speed = car_state['speed']
if self.speed == 0:
self.set_speed(0)
else:
self.set_speed(self.speed_limit)
logging.debug('Current Speed = %d, New Speed = %d' % (old_speed, self.speed))
if self.speed == 0:
logging.debug('full stop for 1 seconds')
time.sleep(1)
def set_speed(self, speed):
# Use this setter, so we can test this class without a car attached
self.speed = speed
if self.car is not None:
logging.debug("Actually setting car speed to %d" % speed)
self.car.back_wheels.speed = speed
 
Обратите внимание, что каждый объект <tt>TrafficObject</tt> просто изменяет <tt>speed и speed_limit</tt> в <tt>car_state</tt> объекте, но на самом деле не меняет скорость автомобиля. Это <tt>ObjectsOnRoadProcessor</tt> изменяет фактическую скорость автомобиля, после обнаружения и обработки всех дорожных знаков и пешеходов.
 
Полный исходный код интереса находится на [https://github.com/dctian/DeepPiCar/blob/master/models/object_detection/code/tensorflow_traffic_sign_detection.ipynb Github DeepPiCar].
==== Итоги ====
В этой статье мы научили наш DeepPiCar распознавать дорожные знаки и пешеходов, а также реагировать на них соответствующим образом. Это не маленький подвиг, так как большинство автомобилей на дороге еще не могут этого сделать. Мы выбрали кратчайший путь и использовали предварительно обученную модель обнаружения объекта и применили обучение передачи на нем. Действительно, трансфертное обучение широко распространено в индустрии ИИ, когда не удается собрать достаточное количество обучающих данных для создания модели глубокого обучения с нуля или не хватает мощности GPU для обучения моделей в течение нескольких недель или месяцев.
 
=== Отслеживание направления взгляда пользователя в браузере ===
 
====Описание====
Решить подобную задачу не так уж и трудно благодаря JavaScript-библиотеке [https://www.tensorflow.org/js/ TensorFlow]. В браузере очень легко получить доступ к веб-камере. Если предположить, что в качестве входных данных для нейронной сети будет использоваться всё изображение с камеры, то можно сказать, что оно для этих целей слишком велико. Системе придётся проделать большую работу только для того, чтобы определить то место на изображении, где находятся глаза. Такой подход может хорошо показать себя в том случае, если речь идёт о модели, которую разработчик обучает самостоятельно и развёртывает на сервере, однако если мы говорим об обучении и использовании модели в браузере — это уже чересчур.
 
Для того чтобы облегчить задачу сети, мы можем предоставить ей лишь часть изображения — ту, которая содержит глаза пользователя [[Файл:Eyes.png |400px|thumb| right| Рис. 7 Процесс выделения глаз.]] и небольшую область вокруг них. Эту область, представляющую собой прямоугольник, окружающий глаза, можно выявить с помощью сторонней библиотеки.
 
Для обнаружения лица на изображении воспользуемся библиотекой, которая называется [https://github.com/auduno/clmtrackr clmtrackr].
 
Если в качестве входа для простой свёрточной нейронной сети используется маленькое, но с умом подобранное изображение, сеть, без особых проблем, сможет обучиться.
 
====Алгоритм:====
 
1. '''Подготовка'''. <br/>Загрузка библиотек, подготовка пустого HTML-документа с которым будем работать.
 
2. '''Получение видеопотока с веб-камеры'''<br/>Запрашиваем разрешение пользователя на активацию веб-камеры. Начинаем получать видео с камеры и создаем функции контроля за потоком.
 
3. '''Поиск лица'''. <br/> Используем библиотеку clmtrackr.js для поиска лица на видео. Для начала инициализируем систему слежения за лицом.<br/><code>const ctrack = new clm.tracker();<br/>ctrack.init();</code><br/>Теперь, в функции onStreaming(), подключяем систему поиска лица, добавляя туда следующую команду:<code>ctrack.start(video);</code>Теперь, каждый раз, когда браузер выводит очередной кадр видео, мы собираемся рисовать что-то на элементе <canvas>. Выполнение какого-либо кода при выводе каждого кадра выполняется с помощью механизма requestAnimationLoop().Теперь вызовем функцию trackingLoop() в функции onStreaming() сразу после ctrack.start(). Эта функция будет сама планировать собственный перезапуск в каждом кадре.<br/>
<tt>
const overlay = $('#overlay')[0];
const overlayCC = overlay.getContext('2d');
function trackingLoop() {
// Проверим, обнаружено ли в видеопотоке лицо,
// и если это так - начнём его отслеживать.
requestAnimationFrame(trackingLoop);
let currentPosition = ctrack.getCurrentPosition();
overlayCC.clearRect(0, 0, 400, 300);
if (currentPosition) {
ctrack.draw(overlay);
}
}
</tt>
4. '''Выявление области изображения, содержащей глаза'''.
[[Файл:Face.png |250px|thumb|right| Рис. 8 Контрольные точки.]]Решим, что глаза — это прямоугольная часть изображения, границы которой касаются точек 23, 28, 24 и 26, расширенная на 5 пикселей в каждом направлении. Этот прямоугольник должен включать в себя всё, что для нас важно, если только пользователь не слишком сильно наклоняет голову.
 
Следующая функция вернёт координаты x и y, а также ширину и высоту прямоугольника, окружающего глаза. Она, в качестве входных данных, принимает массив positions, полученный от clmtrackr. Обратите внимание на то, что каждая координата, полученная от clmtrackr, имеет компоненты x и y.
function getEyesRectangle(positions) {
const minX = positions[23][0] - 5;
const maxX = positions[28][0] + 5;
const minY = positions[24][1] - 5;
const maxY = positions[26][1] + 5;
const width = maxX - minX;
const height = maxY - minY;
return [minX, minY, width, height];
}
 
Теперь, в каждом кадре, мы собираемся извлекать из видеопотока прямоугольник с глазами, обводить его красной линией на элементе <canvas>, который наложен на элемент <video>, а затем копировать его в новый элемент <canvas>.
 
if (currentPosition) {
// Выведем линии, проведённые между контрольными точками
// на элементе <canvas>, наложенном на элемент <video>
ctrack.draw(overlay);
// Получим прямоугольник, ограничивающий глаза, и обведём его
// красными линиями
const eyesRect = getEyesRectangle(currentPosition);
overlayCC.strokeStyle = 'red';
overlayCC.strokeRect(eyesRect[0], eyesRect[1], eyesRect[2], eyesRect[3]);
// Видеопоток может иметь особые внутренние параметры,
// поэтому нам нужны эти константы для перемасштабирования
// прямоугольника с глазами перед обрезкой
const resizeFactorX = video.videoWidth / video.width;
const resizeFactorY = video.videoHeight / video.height;
// Вырезаем прямоугольник с глазами из видео и выводим его
// в соответствующем элементе <canvas>
const eyesCanvas = $('#eyes')[0];
const eyesCC = eyesCanvas.getContext('2d');
eyesCC.drawImage(
video,
eyesRect[0] * resizeFactorX, eyesRect[1] * resizeFactorY,
eyesRect[2] * resizeFactorX, eyesRect[3] * resizeFactorY,
0, 0, eyesCanvas.width, eyesCanvas.height
);
}
 
5. '''Сбор данных'''
 
Пользователь перемещает курсор по странице и следит за ним глазами, нажимая на клавишу <tt>Пробел</tt> на клавиатуре каждый раз, когда программа должна записать очередной образец. При таком подходе несложно быстро собрать большой набор данных для обучения модели.
 
6.'''Отслеживание перемещений мыши'''
 
Для того чтобы узнать, где именно на веб-странице расположен указатель мыши, нам понадобится обработчик события document.onmousemove. Функция нормализует координаты таким образом, чтобы они укладывались в диапазон [-1, 1].
<tt>
const mouse = {
x: 0,
y: 0,
handleMouseMove: function(event) {
// Получим позицию указателя и нормализуем её, приведя к диапазону [-1, 1]
mouse.x = (event.clientX / (window).width()) * 2 - 1;
mouse.y = (event.clientY / (window).height()) * 2 - 1;
},
}
document.onmousemove = mouse.handleMouseMove;
</tt>
7. '''Захват изображения'''
 
Для захвата изображения, выводимого элементом <canvas> и сохранения его в виде тензора, TensorFlow.js предлагает вспомогательную функцию tf.fromPixels(). Используем её для сохранения и последующей нормализации изображения.
function getImage() {
// Захват текущего изображения в виде тензора
return tf.tidy(function() {
const image = tf.fromPixels($('#eyes')[0]);
// Добавление <i><font color="#999999">измерения</font></i>:
const batchedImage = image.expandDims(0);
// Нормализация и возврат данных:
return batchedImage.toFloat().div(tf.scalar(127)).sub(tf.scalar(1));
});
}
Код который собирает данные и формирует выборки:
const dataset = {
train: {
n: 0,
x: null,
y: null,
},
val: {
n: 0,
x: null,
y: null,
},
}
function captureExample() {
// Возьмём самое свежее изображение глаз и добавим его в набор данных
tf.tidy(function() {
const image = getImage();
const mousePos = tf.tensor1d([mouse.x, mouse.y]).expandDims(0);
// Решим, в какую выборку (обучающую или контрольную) его добавлять
const subset = dataset[Math.random() > 0.2 ? 'train' : 'val'];
if (subset.x == null) {
// Создадим новые тензоры
subset.x = tf.keep(image);
subset.y = tf.keep(mousePos);
} else {
// Конкатенируем их с существующими тензорами
const oldX = subset.x;
const oldY = subset.y;
subset.x = tf.keep(oldX.concat(image, 0));
subset.y = tf.keep(oldY.concat(mousePos, 0));
}
// Увеличим счётчик
subset.n += 1;
});
}
Привяжем данную функцию к какой-нибудь клавише, например <tt>пробел</tt>.
$('body').keyup(function(event) {
// Выполняется при нажатии на клавишу Пробел на клавиатуре
if (event.keyCode == 32) {
captureExample();
event.preventDefault();
return false;
}
});
8. '''Обучение модели'''
 
Создадим простую [https://ru.wikipedia.org/wiki/Свёрточная_нейронная_сеть свёрточную нейронную сеть]. TensorFlow.js предоставляет для этой цели API, напоминающее Keras. У сети есть слой conv2d, слой maxPooling2d, и слой dense c двумя выходными значениями (они представляют экранные координаты), в качестве регуляризатора, слой dropout, и слой flatten для того, чтобы преобразовать двухмерные данные в одномерные. Обучение сети выполняется с помощью оптимизатора Adam.
let currentModel;
function createModel() {
const model = tf.sequential();
model.add(tf.layers.conv2d({
kernelSize: 5,
filters: 20,
strides: 1,
activation: 'relu',
inputShape: [('#eyes').height(),('#eyes').width(), 3],
}));
model.add(tf.layers.maxPooling2d({
poolSize: [2, 2],
strides: [2, 2],
}));
model.add(tf.layers.flatten());
model.add(tf.layers.dropout(0.2));
// Два выходных значения x и y
model.add(tf.layers.dense({
units: 2,
activation: 'tanh',
}));
// Используем оптимизатор Adam с коэффициентом скорости обучения 0.0005 и с функцией потерь MSE
model.compile({
optimizer: tf.train.adam(0.0005),
loss: 'meanSquaredError',
});
return model;
}
 
Также прежде чем приступать к обучению сети, зададим фиксированное количество эпох и переменный размер пакета (так как мы, возможно, будем работать с очень маленькими наборами данных).
 
function fitModel() {
let batchSize = Math.floor(dataset.train.n * 0.1);
if (batchSize < 4) {
batchSize = 4;
} else if (batchSize > 64) {
batchSize = 64;
}
if (currentModel == null) {
currentModel = createModel();
}
currentModel.fit(dataset.train.x, dataset.train.y, {
batchSize: batchSize,
epochs: 20,
shuffle: true,
validationData: [dataset.val.x, dataset.val.y],
});
}
 
Теперь добавим на страницу кнопку для запуска обучения. Этот код идёт в HTML-файл:
 
<button id="train">Train!</button>
<style>
#train {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-size: 24pt;
}
</style>
 
Этот код добавляем в JS-файл:
 
$('#train').click(function() {
fitModel();
});
 
9. ''' Предсказываем куда смотрит пользователь'''.
 
Теперь, когда мы можем собирать данные и подготовили модель, можно начать предсказывать место на странице, куда смотрит пользователь. Укажем на это место с помощью зелёного кружка, который перемещается по экрану.
 
Сначала добавим на страницу кружок:
 
<div id="target"></div>
<style>
#target {
background-color: lightgreen;
position: absolute;
border-radius: 50%;
height: 40px;
width: 40px;
transition: all 0.1s ease;
box-shadow: 0 0 20px 10px white;
border: 4px solid rgba(0,0,0,0.5);
}
</style>
 
Для того чтобы перемещать его по странице, мы периодически передаём текущее изображение глаз нейронной сети и задаём ей вопрос о том, куда смотрит пользователь. Модель в ответ выдаёт две координаты, по которым должен быть перемещён кружок:
 
function moveTarget() {
if (currentModel == null) {
return;
}
tf.tidy(function() {
const image = getImage();
const prediction = currentModel.predict(image);
// Конвертируем нормализованные координаты в позицию на экране
const targetWidth = ('#target').outerWidth();
const targetHeight = ('#target').outerHeight();
const x = (prediction.get(0, 0) + 1) / 2 * ((window).width() - targetWidth);
const y = (prediction.get(0, 1) + 1) / 2 * ((window).height() - targetHeight);
// Переместим в нужное место кружок:
const target = ('#target');
target.css('left', x + 'px');
target.css('top', y + 'px');
});
}
setInterval(moveTarget, 100);
 
====Итоги====
 
На выходе мы получили систему слежения за человеческим взглядом, у которой даже есть практическое применение.
Например при исследовании пользовательского опыта, во время проектирования и разработки интерфейсов веб-сайтов применяются тепловые карты.
[https://spyserp.com/ru/blog/heatmap-tool '''Тепловая карта сайта'''] - это инструмент, который использует цветовую палитру для визуализации данных на графике. Например, если вы смотрите на веб-страницу и хотите знать, какие элементы привлекают больше всего внимания, тепловая карта покажет эту информацию на основании пользовательских данных.
Полный код разобранного в этом материале примера можно найти [https://github.com/cpury/lookie-lookie/tree/master/blogcode здесь].
Посмотреть на реализованную полную версию разобранного примера можно [https://cpury.github.io/lookie-lookie/ здесь].
== Источники информации==
* [https://ru.qwe.wiki/wiki/Augmented_reality Дополненная реальность.]
* [https://ru.qwe.wiki/wiki/Positional_tracking Positional tracking.]
* [http://sv-journal.org/2015-4/09/index.php?lang=ru Автоматическая оценка ракурса лица в кадре и приведение изображения к нулевым углам поворота.]
* [http://docs.cntd.ru/document/gost-r-54621-2011 ГОСТ Р 54621-2011. Информационные технологии. Радиочастотная идентификация для управления предметами.]
* [https://habr.com/ru/post/482220/ Локализация по Aruco маркерам]
* [https://habr.com/ru/post/397757/ Обзор методов и технологий отслеживания положения для виртуальной реальности.]
* [https://nanonets.com/blog/object-tracking-deepsort/ DeepSORT: Deep Learning to Track Custom Objects in a Video.]
* [https://github.com/cpury/lookie-lookie/tree/master/blogcode Проект по трекингу взгляда]
* [https://habr.com/ru/company/ruvds/blog/426055/ TensorFlow.js и clmtrackr.js: отслеживание направления взгляда]
* [https://towardsdatascience.com/deeppicar-part-6-963334b2abe0 DeepPiCar — Part 6: Traffic Sign and Pedestrian Detection and Handling]
{{В разработке}}
 
[[Категория:Компьютерное зрение]]
15
правок

Навигация