Да, действительно, мы смогли заменить нейронной сетью спортивного скаута и стали автоматически собирать данные об игре. И теперь знаем о спортивном состязании больше присутствующего на нем зрителя, а иногда и судьи.
Мы (Constanta) специализируемся на разработке букмекерских IT-продуктов: мобильных приложений, сайтов и в последнее время развиваем проекты в области компьютерного зрения и машинного обучения. Об одном из них и пойдет речь.
Пока спортсмены сражаются за большие и маленькие победы, букмекеру нужно в режиме реального времени знать ход событий, чтобы пересчитывать коэффициенты, по которым, собственно, и принимаются ставки. Для этого спортивные скауты непосредственно на игровых площадках собирают и передают с помощью специального приложения на смартфоне большой объем данных. Скаут – такой же человек, как все мы, поэтому естественным образом возникают связанные с человеческим фактором риски. Наша цель – свести их к минимуму, попутно увеличив объем и оперативность сбора и передачи данных, плюс — снизить себестоимость всей этой работы. Летает маленький шарик над теннисным столом или мяч по футбольному полю — техническая сторона реализации системы компьютерного зрения для сбора данных не имеет концептуальных отличий. Мы решили, что интереснее сразу строить систему для игры с большим количеством взаимодействующих шаров, как в бильярде.
Мне нужны координаты и скорости всех твоих шаров и твоего кия.
Заметим, что при анализе многих спортивных игр для правильного определения результата необходимо безошибочно отследить цепочку событий. Отсюда вытекают высокие требования к надежности работы компонентов, отвечающих за определение этих событий. Поясним на простом примере: если в бильярде в среднем игроки закатывают все шары в лузы за 20 ударов, то при надежности определения исхода удара 99% вероятность определить победителя в розыгрыше составляет всего около 82% (0,9920≈0,817). Матч продолжается до пяти побед одного из игроков, то есть всего происходит от 5 до 9 розыгрышей, в среднем 7. Таким образом, в среднем при такой надежности определения событий правильный результат матча получается с вероятностью всего лишь около 24% (0,8177≈0,24). А ведь изначально вероятность ошибки составляла лишь 1%!
Пул “девятка”
Из всего многообразия бильярдных игр рассмотрим Пул-9. В розыгрыше побеждает игрок, битком закативший шар с номером 9 в лузу. Изначально “девятка” располагается в центре ромба из цветных шаров. Прицельным шаром, по которому должен ударить биток, является шар с наименьшим номером из имеющихся на столе. Если игрок не смог забить в результате удара ни один цветной шар или совершил фол, например не попал по прицельному шару или забил биток в лузу, ход переходит к оппоненту. Чтобы правильно засчитать очко, необходимо определять попадания шаров в лузы и все события, приводящие к смене игрока.
Компьютерное зрение
Для начала расскажем о том, как нейронная сеть получает данные. Входной информационный поток – видеотрансляция с одной камеры, расположенной над столом и снимающей с частотой 60 кадров в секунду.
Пример кадра видеопотока, обрабатываемого системой.
Ключевой этап обработки видеопотока нейронной сетью — семантическая сегментация. Это классическая задача компьютерного зрения, состоящая в том, что алгоритм должен отнести пиксели изображения к одному или нескольким классам. Проще говоря, на видеокадрах необходимо определить, что есть что. Нейронная сеть выдает “маски”, выделяя пиксели, относящиеся, например, к шару или игроку. Пройдя через серию постпроцессинговых алгоритмов “маски” шаров превращаются в координаты. По ним после сглаживания фильтром для каждого шара определяются скорость и траектория движения. На этом этапе отслеживаются низкоуровневые, или промежуточные, события, такие как столкновения шаров между собой и с бортами стола. Полученные данные отправляются в модуль обработки правил, который реализует всю логику игры. Он в итоге и выдает конечному потребителю, т.е. букмекеру, высокоуровневые события: забивание шаров в лузы, фолы, переходы ходов и, собственно, результат игры.
Общая схема системы.
Для решения задачи в первую очередь необходимо найти местоположение стола на кадре и всех шаров на нем. Еще один важный участник действия — кий, именно он определяет направление удара и, соответственно, траекторию движения битка. Над столом наклоняются игроки, частично закрывая его от камеры. С точки зрения анализа игры они представляют собой “посторонние предметы”, как и подставка для шаров, а также мобильные телефоны, перчатки, салфетки и прочие вещи, которые по воле игроков появляются на бортах стола. Таким образом, получается несколько целевых классов для семантической сегментации изображений: стол, его борта, лузы, кий, посторонние предметы и, разумеется, шары. При этом каждый шар представлен отдельным классом в зависимости от его цвета.
Для семантической сегментации используется полностью сверточная нейронная сеть с архитектурой LinkNet-34. Она относительно быстро работает и хорошо зарекомендовала себя в различных “боевых” задачах конкурсов по компьютерному зрению. Для определения перечисленного выше множества классов используется всего одна нейронная сеть, решающая все задачи компьютерного зрения.
Архитектура сети LinkNet-34 (см. arXiv).
На вход подаются изображения, а на выходе получается стопка “масок” всех требуемых классов. “Маски-предсказания” представляют собой двумерные массивы чисел со значениями от 0 до 1. Величина каждого элемента “маски” соответствует уверенности сети в том, что соответствующий пиксель относится к классу данной “маски”. Для итоговой классификации пикселей полученные предсказания бинаризируются пороговым фильтром.
Обучить нейронную сеть классифицировать пиксели можно на большом количестве примеров с соответствующими “масками”. Для этого мы собрали множество видео, разделили на кадры, а отдел разметки вручную подготовил “маски” для них. В сложных случаях потребовались дополнительные наборы данных. Например, когда шар “ныряет” в лузу или стоит около нее рядом с бортом стола, на него падает тень, из-за которой цвета выглядят иначе. Или, когда игрок разбивает ромб, шары летят быстро по сложным траекториям, из-за чего их изображения смазываются. Если нейронная сеть “видела” немного таких примеров, корректная классификация будет затруднительна.
Пример изображения и соответствующей ему разметки. Задача нейронной сети состоит в том, чтобы из входного изображение получать такие “маски”.
Быстро, быстрее, еще быстрее…
Конечному потребителю данных информация нужна в реальном времени (а еще лучше — быстрее риал-тайм). Для ускорения работы нейронной сети применено несколько техник, таких как объединение пакетной нормализации с 2D-сверткой (BatchNorm Fusion), что позволяет получить эквивалентную сеть без нескольких слоев. Хороший результат дает также подготовка и загрузка нового кадра параллельно с обработкой предыдущего на видеокарте. Помимо этого, на gpu выполняется часть подготовительных операций с кадрами и постобработки “масок”. Сократить суммарное время на обработку каждого кадра помогла даже простая идея — переносить результат работы сети с видеокарты в оперативную память после бинаризации в виде uint8 вместо получаемого из сети float32.
В результате семантическая сегментация одного кадра со всей требуемой пред- и постобработкой занимает в среднем всего 17 мс! А для работы системы достаточно лишь одной игровой видеокарты.
А было ли столкновение?
Координаты шаров мы определяем по “маскам”, но предварительно нужно исключить то, что лишь напоминает шар, например круглые нашивки на футболках игроков. Тут в дело вступают эвристики: проверяется форма и размер шаров, их положение относительно прошлого, хорошо известного. Далее, если с “маской” все в порядке, для обработки берется ее центроид.
Игрок в бильярд в страшных снах разработчиков.
На первый взгляд странно, но факт — результат определения положения шаров может отличаться между кадрами даже при неподвижных шарах. Объяснение простое — “зашумленность” реального видео, артефакты сжатия видеопотока, что вместе с погрешностью в определении положения смазанных изображений движущихся шаров приводит к необходимости сглаживать полученные результаты.
По координатам шаров, полученных от сети и определенных на предыдущих кадрах, оценивается скорость как численная производная. Количество учитываемых точек и интервал между ними подбираются адаптивно в процессе работы системы в зависимости от наличия данных и таких событий, как столкновения. Затем информация о положении и скорости шаров отправляется в сигма-точечный фильтр Калмана. Он позволяет сгладить зашумленные данные, что особенно важно для определения скорости и ее направления. К тому же результат работы динамической модели из него может быть использован для предсказания ближайшего будущего.
Демонстрация сглаживания определения положения и скорости шаров фильтром Калмана.
Слева: Raw: результат прямого измерения, векторы у шаров соответствуют скорости, цифры — обозначают оценку величины скорости; UKF: результат работы фильтра.
Справа: пример сглаживания направления скорости шара фильтром Калмана. Синим цветом изображены результаты измерений, красным — результат фильтрации. Резкие скачки направления соответствуют столкновениям шара.
Данные о состоянии и траектории шаров позволяют определить наступление так называемого низкоуровневого события, даже когда оно попало “между кадрами”.
Шары во время удара перемещаются так быстро, что зачастую нет кадра, на котором видно непосредственно событие, например, столкновение шаров. Поэтому для всех типов взаимодействий (столкновение шаров между собой, с бортом или попадание в лузу) вначале строится список возможных событий. Критериев здесь два. Во-первых, критически близкое взаимное расположение шаров. При медленном перемещении возникает большая относительная погрешность в определении скорости и траектории, поэтому важно расстояние между взаимодействующими объектами. Во-вторых, при большой скорости движения шаров возможные события определяются по пересечению траекторий, полученных из динамической модели. Такой подход дает весьма приятный бонус: возможность немного заранее предсказать вероятное попадание шара в лузу.
Последовательные кадры видеопотока при начальном разбитии ромба из шаров. Без модели, описывающей траектории шаров, определить, с каким шаром столкнулся биток, затруднительно.
Изменение направления и величины вектора скорости позволяет судить, что событие, а именно столкновение, произошло. В случае, когда шар закатился в лузу, он “пропадает”. Но тут есть важный момент: необходимо использовать данные о его траектории и проверять, что шар был именно забит, а не исчез из поля зрения камеры из-за того, что над ним случайно оказалась рука игрока или иной предмет.
А если что-то пошло не так? Скажем, часть событий выпала из-за потери кадра или нависшей над столом фигуры игрока. Такие пропуски критичны для игровой логики. Спасает эвристическая система автокоррекции, повышающая устойчивость системы. Например, если определен удар по битку и падение прицельного шара в лузу, но при этом не зафиксировано столкновений битка и другие шары остались неподвижны, логично добавить столкновение битка с прицельным шаром.
Так мы играем или нет?
Шары катятся, сталкиваются, попадают в лузы… А идет ли на самом деле в этот момент игра? Или, напротив, все на столе кажется незыблемо… Значит игра остановилась? Правильный ответ на эти вопросы, вероятно, так же важен, как и определение столкновений. Когда игрок готовится к удару, обдумывает его, целится, движения нет. Но бывает и наоборот, в неигровые моменты жизнь на столе может идти весьма динамично: забитые шары перемещают из одной лузы в другую, биток могут катать по столу при его установке после фола, причем делают это в том числе кончиком кия (очень похоже на удар!). Если окончание текущего удара легко можно определить — после корректного удара все шары перестают двигаться, то с началом все не так однозначно. Конечно, можно обучить нейронную сеть обнаруживать события в видео, в том числе и настоящие удары кия по битку. А можно составить набор эвристик, которые анализируют положение и угол кия, траекторию и скорость его концов и траекторию битка после предполагаемого удара. Мы пошли вторым путем, и в результате получился очень быстрый и надежный алгоритм, определяющий текущее состояние игры.
Система пытается понять, началась игра или нет.
И кто в итоге выиграл?
Все данные о низкоуровневых событиях (удар по битку, положения и столкновения шаров, попадания в лузы) отправляются в модуль, который по их последовательности определяет, что произошел фол или корректное падение шара в лузу, переход хода или окончание игры. Беспристрастный модуль ведет счет и объявляет победителя. Особенность его в том, что он работает без всяких автокоррекций и эвристик, просто формально применяя правила игры. Блок с правилами можно целиком заменить, что позволяет без существенного вмешательства в систему адаптировать ее к локальным правилам турнира или использовать для обработки других видов бильярдных игр.
Как беспилотные автомобили до сих пор полностью не избавились от инженера-испытателя в салоне, который следит за безопасностью, так и наш модуль правил позволяет осуществлять внешнее ручное управление через web-интерфейс. Вмешательство может потребоваться, если автоматическая система ошибется. Кроме того, необходим ручной ввод отсутствующих в видеопотоке данных: о начинающем игроке, специальных ударах, которые объявляются по ходу игры голосом и т.п. Один человек потенциально может следить за несколькими играми одновременно.
Как это работает
После успешного запуска и настройки системы мы не только стали получать требуемые данные, но сверх того обнаружили много интересного. Так, иногда судья, находясь у стола, не может точно определить, попал биток по прицельному шару или же по другому, стоящему рядом. В то время как объективный взгляд нашей системы позволяет увидеть, как же ситуация развивалась на самом деле. Кроме того, система собирает много полезных для дальнейшего анализа сведений, которые человек просто не в состоянии определить и передать в реальном времени: положения и скорости шаров, параметры ударов кия каждым из игроков.
В настоящее время система работает и используется букмекером. В дальнейшем планируется усовершенствовать систему, в том числе добавить автоматическую идентификацию игроков, автоматическое определение результатов розыгрыша первого удара.
Техническая визуализация того, как работает система. Шар около «Cue ball» обозначает с каким первым шаром столкнулся биток; «State» — состояние системы: может быть «wait» — пока игрок не совершил удар и «play» — пока шары находятся в двжении; «Player» — текущий игрок; цифры около шаров обозначают оценку скорости в см/с.
Автор: NikolasEnt