Разработка системы видео-мониторинга парковочного пространства


Download 1.02 Mb.
bet7/7
Sana16.04.2023
Hajmi1.02 Mb.
#1358407
1   2   3   4   5   6   7
Bog'liq
m th o.v.solovichenko 2017 RU

Оптическое распознавание маркеров
Каждое парковочное место в соответствии с рисунком 14 отмечено специальным знаком-маркером. Если автомобиль занимает парковочное место, то он полностью закрывает специальный знак и можно считать это место занятым.
Для данного подхода необходимо чтобы все парковочные места были под видеонаблюдением. Если камер на парковке достаточно, то технология оптического распознавания не потребует установки дополнительного оборудования. Данный подход не подойдет для открытых парковок, так как снег и лужи могут перекрыть графические метки.

Рисунок 13 - Пример табло и парковочных мест в разрабатываемой системе




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

Таблица 2 – Сравнение подходов мониторинга парковочных мест








Оптическое
распознавание

Ультразвуковые
датчики

Использование
открытой парковке

на

Не рекомендуется

Рекомендуется

Электропитание

Работа от сети

Работа от батареек

Затраты
оборудование

на

Нет, если камеры
охватывают все места

Требуется датчик
каждое место

на

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



  1. Оптическое распознавание меток

Метка Aruca представляет собой синтетический квадратный маркер состоящий из широкой черной рамки и внутренней двоичной матрицы в соответствии с рисунком 13, которая определяет его идентификатор (ID). Черная облегчает ее быстрое обнаружение в изображении, а двоичная кодификация позволяет его идентифицировать и применять методы обнаружения и коррекции ошибок. Размер маркера определяется размером внутренней матрицы. Например, размер маркера 4x4 состоит из 16 бит.


Рисунок 14 - Aruco маркеры


Следует отметить, что метка может быть найдена даже если изменить угол поворота, однако, процесс обнаружения должен быть в состоянии определить первоначальный угол, так что каждый угол определяется однозначно. Это также делается на основе двоичной кодификации.
Словарь маркеров представляет собой набор маркеров, которые рассматриваются в конкретном приложении. Это просто список бинарных кодификаций каждого маркера.
Основными свойствами словаря являются размер словаря и размер маркера. Размер словаря - это количество маркеров, составляющих словарь. Размер маркера - это размер этих маркеров (количество бит).
Модуль aruco включает в себя некоторые предопределенные словари, охватывающие диапазон маркеров различных размеров.
Учитывая изображение, на котором видно некоторые маркеры ArUco, в результате процесс обнаружения должен вернуть список обнаруженных маркеров.
Каждый обнаруженный маркер включает в себя:

  • Положение его четырех углов на изображении (в исходном порядке);

  • Идентификатор маркера;

Процесс обнаружения маркера состоит из двух основных этапов:


Первый этап обнаружение маркер-кандидатов. На этом этапе изображение анализируется, чтобы найти квадратные фигуры, которые являются кандидатами на роль маркеров. Этап начинается с адаптивного порога для сегментации маркеров, затем контуры извлекаются из порогового изображения, а те, которые не являются выпуклыми или не аппроксимируются квадратной формой, отбрасываются. Также применяется некоторая дополнительная фильтрация (удаление слишком малых или слишком больших контуров, удаление контуров слишком близко друг к другу и т. д.).
На втором этапе, после обнаружения кандидатов, необходимо определить, являются ли они на самом деле маркерами, анализируя их внутреннюю кодификацию. Этот шаг начинается с извлечения маркерных битов каждого маркера. Для этого, во-первых, применяется перспективное преобразование для получения маркера в его канонической форме. Затем для канонического изображения находится пороговое значение с помощью метода Otsu для разделения белых и черных битов. Изображение делится на ячейки в соответствии с размером маркера и размером границы. Количеством черных или белых пикселей на каждой ячейке подсчитывается, чтобы определить, является ли ячейка белой или черной. Наконец, биты анализируют, чтобы определить, принадлежит ли маркер конкретному словарю, и при необходимости используются методы коррекции ошибок [8].

  1. Обзор использованного программного обеспечения

    1. Среда разработки

В качестве среды разработки системы видео-мониторинга парковочного пространства использовалась среда разработки Microsoft Visual Studio 2015.
Microsoft Visual Studio — линейка продуктов компании Microsoft, включающих интегрированную среду разработки программного обеспечения и ряд других инструментальных средств. Данные продукты позволяют разрабатывать как консольные приложения, так и приложения с графическим интерфейсом, в том числе с поддержкой технологии Windows Forms, а также веб-сайты, веб-приложения, веб-службы как в родном, так и в управляемом кодах для всех платформ, поддерживаемых Windows, Windows Mobile, Windows CE, .NET Framework, Xbox, Windows Phone .NET Compact Framework и Silverlight.
Visual Studio включает в себя редактор исходного кода с поддержкой технологии IntelliSense и возможностью простейшего рефакторинга кода. Встроенный отладчик может работать как отладчик уровня исходного кода, так и отладчик машинного уровня. Остальные встраиваемые инструменты включают в себя редактор форм для упрощения создания графического интерфейса приложения, веб-редактор, дизайнер классов и дизайнер схемы базы данных. Visual Studio позволяет создавать и подключать сторонние дополнения (плагины) для расширения функциональности практически на каждом уровне, включая добавление поддержки систем контроля версий исходного кода (как, например, Subversion и Visual SourceSafe), добавление новых наборов инструментов (например, для редактирования и визуального проектирования кода на предметно-ориентированных языках программирования) или инструментов для прочих аспектов процесса разработки программного обеспечения (например, клиент Team Explorer для работы с Team Foundation Server) [9].

    1. Платформа .NET Framework

Платформа .NET Framework — это технология, которая поддерживает создание и выполнение нового поколения приложений и веб-служб XML. При разработке платформы .NET Framework учитывались следующие цели.
Обеспечение согласованной объектно-ориентированной среды программирования для локального сохранения и выполнения объектного кода, для локального выполнения кода, распределенного в Интернете, либо для удаленного выполнения.
Обеспечение среды выполнения кода, минимизирующей конфликты при развертывании программного обеспечения и управлении версиями.
Обеспечение среды выполнения кода, гарантирующей безопасное выполнение кода, включая код, созданный неизвестным или не полностью доверенным сторонним изготовителем.
Обеспечение среды выполнения кода, исключающей проблемы с производительностью сред выполнения сценариев или интерпретируемого кода.
Обеспечение единых принципов работы разработчиков для разных типов приложений, таких как приложения Windows и веб-приложения.
Разработка взаимодействия на основе промышленных стандартов, которое обеспечит интеграцию кода платформы .NET Framework с любым другим кодом.
Платформа .NET Framework состоит из общеязыковой среды выполнения (среды CLR) и библиотеки классов .NET Framework. Основой платформы .NET Framework является среда CLR. Среду выполнения можно считать агентом, который управляет кодом во время выполнения и предоставляет основные службы, такие как управление памятью, управление потоками и удаленное взаимодействие. При этом накладываются условия строгой типизации и другие виды проверки точности кода, обеспечивающие безопасность и надежность. Фактически основной задачей среды выполнения является управление кодом. Код, который обращается к среде выполнения,
называют управляемым кодом, а код, который не обращается к среде выполнения, называют неуправляемым кодом. Библиотека классов является комплексной объектно-ориентированной коллекцией допускающих повторное использование типов, которые применяются для разработки приложений — начиная с обычных приложений, запускаемых из командной строки, и приложений с графическим интерфейсом пользователя (GUI), и заканчивая приложениями, использующими последние технологические возможности ASP.NET, такие как Web Forms и веб-службы XML.
Платформа .NET Framework может размещаться неуправляемыми компонентами, которые загружают среду CLR в собственные процессы и запускают выполнение управляемого кода, создавая таким образом программную среду, позволяющую использовать средства как управляемого, так и неуправляемого выполнения. Платформа .NET Framework не только предоставляет несколько базовых сред выполнения, но также поддерживает разработку базовых сред выполнения независимыми производителями.
Например, ASP.NET размещает среду выполнения и обеспечивает масштабируемую среду для управляемого кода на стороне сервера. ASP.NET работает непосредственно со средой выполнения, чтобы обеспечить выполнение приложений ASP.NET и веб-служб XML, обсуждаемых ниже в этом разделе.
Обозреватель Internet Explorer может служить примером неуправляемого приложения, размещающего среду выполнения (в виде расширений типов MIME). Размещение среды выполнения в обозревателе Internet Explorer позволяет внедрять управляемые компоненты или элементы управления Windows Forms в HTML-документы. Такое размещение среды позволяет выполнять управляемый мобильный код и пользоваться его существенными преимуществами, в частности выполнением в условиях неполного доверия и изолированным хранением файлов.
Среда CLR и библиотеки взаимосвязаны с пользовательскими приложениями и всей системой. Управляемый код работает в пределах более широкой архитектуры в соответствии с рисунком 15.

Рисунок 15 - .NET Framework в контексте
Среда CLR управляет памятью, выполнением потоков, выполнением кода, проверкой безопасности кода, компиляцией и другими системными службами. Эти средства являются внутренними для управляемого кода, который выполняется в среде CLR.
По соображениям безопасности управляемым компонентам присваиваются разные степени доверия, зависящие от ряда факторов, в число которых входит их происхождение (например, Интернет, сеть предприятия или локальный компьютер). Это означает, что управляемый компонент может или не может выполнять операции доступа к файлам, операции доступа к реестру или другие важные функции, даже если он используется в одном активном приложении.
Среда выполнения обеспечивает управление доступом для кода. Например, пользователи могут доверить исполняемому приложению,
внедренному в веб-страницу, воспроизведение анимации на экране или звукозаписи, не позволяя ему при этом получить доступ к личным данным, файловой системе или сети. Таким образом, средства безопасности CLR предоставляют подлинному развернутому в Интернете программному обеспечению исключительно богатые функции.
Среда выполнения также обеспечивает надежность кода, реализуя инфраструктуру строгой типизации и проверки кода, которую называют системой общих типов (CTS). Система общих типов обеспечивает самоописание всего управляемого кода. Различные языковые компиляторы корпорации Microsoft и независимых изготовителей создают управляемый код, удовлетворяющий системе общих типов. Это означает, что управляемый код может принимать другие управляемые типы и экземпляры, при этом обеспечивая правильность типов и строгую типизацию.
Кроме того, управляемая среда выполнения исключает многие часто возникающие проблемы с программным обеспечением. Например, среда выполнения автоматически управляет размещением объектов и ссылками на объекты, освобождая их, когда они больше не используются. Автоматическое управление памятью исключает две наиболее часто возникающие ошибки приложений: утечки памяти и недействительные ссылки на память.
Среда выполнения также повышает продуктивность разработчиков. Например, программисты могут писать приложения на привычном языке разработки, при этом используя все преимущества среды выполнения, библиотеку классов и компоненты, написанные другими разработчиками на других языках. Это доступно любому производителю компиляторов, обращающихся к среде выполнения. Языковые компиляторы, предназначенные для платформы .NET Framework, делают средства .NET Framework доступными для существующего кода, написанного на соответствующих языках, существенно облегчая процесс переноса существующих приложений.
Хотя среда выполнения разрабатывалась для будущего программного обеспечения, она также поддерживает сегодняшнее и вчерашнее программное обеспечение. Взаимодействие управляемого и неуправляемого кодов позволяет разработчикам использовать необходимые компоненты COM и библиотеки DLL.
Среда выполнения разработана для повышения производительности. Хотя общеязыковая среда выполнения предоставляет многие стандартные службы времени выполнения, управляемый код никогда не интерпретируется. Средство компиляции по требованию (JIT) позволяет всему управляемому коду выполняться на машинном языке компьютера. Между тем диспетчер памяти устраняет возможность фрагментации памяти и увеличивает объем адресуемой памяти для дополнительного повышения производительности.
И наконец, среда выполнения может размещаться в высокопроизводительных серверных приложениях, таких как Microsoft SQL Server и службы IIS (Internet Information Services). Такая инфраструктура позволяет использовать управляемый код для написания собственной логики программ, пользуясь при этом высочайшей производительностью лучших производственных серверов, которые поддерживают размещение среды выполнения.
Библиотека классов платформы .NET Framework представляет собой коллекцию типов, которые тесно интегрируются со средой CLR. Библиотека классов является объектно-ориентированной; предоставляя типы, из которых управляемый код пользователя может наследовать функции. Это не только упрощает работу с типами .NET Framework, но также уменьшает время, затрачиваемое на изучение новых средств платформы .NET Framework. Кроме того, компоненты независимых производителей можно легко объединять с классами платформы .NET Framework.
Например, в классах коллекций .NET Framework реализуется набор интерфейсов, которые можно использовать для разработки пользовательских
классов коллекций. Пользовательские классы коллекций будут без затруднений объединяться с классами .NET Framework [10].
Как и ожидается от объектно-ориентированной библиотеки классов, типы .NET Framework позволяют решать типовые задачи программирования, включая работу со строками, сбор данных, подключения к базам данных и доступ к файлам. В дополнение к этим обычным задачам библиотека классов содержит типы, поддерживающие многие специализированные сценарии разработки.
Например, можно использовать платформу .NET Framework для разработки следующих типов приложений и служб:

  • консольные приложения;

  • приложения с графическим интерфейсом пользователя Windows (Windows Forms);

  • приложения Windows Presentation Foundation (WPF);

  • приложения ASP.NET; См. раздел Разработка веб-приложений с помощью ASP.NET;

  • службы Windows;

  • сервисноориентированные приложения с помощью Windows Communication Foundation (WCF);

  • приложения поддерживающие бизнес-процессы Windows Workflow Foundation (WF);




    1. Язык программирования

Система видео-мониторинга парковочного пространства была написана на языке программирования C#.
C# — объектно-ориентированный язык программирования. Разработан в 1998—2001 годах группой инженеров под руководством Андерса Хейлсберга в компании Microsoft как язык разработки приложений для платформы Microsoft .NET Framework и впоследствии был стандартизирован как ECMA-334 и ISO/IEC 23270.
C# относится к семье языков с C-подобным синтаксисом, из них его синтаксис наиболее близок к C++ и Java. Язык имеет статическую типизацию, поддерживает полиморфизм, перегрузку операторов (в том числе операторов явного и неявного приведения типа), делегаты, атрибуты, события, свойства, обобщённые типы и методы, итераторы, анонимные функции с поддержкой замыканий, LINQ, исключения, комментарии в формате XML [11].
Переняв многое от своих предшественников — языков C++, Pascal, Модула, Smalltalk и, в особенности, Java — С#, опираясь на практику их использования, исключает некоторые модели, зарекомендовавшие себя как проблематичные при разработке программных систем, например, C# в отличие от C++ не поддерживает множественное наследование классов (между тем допускается множественное наследование интерфейсов).
Существует несколько реализаций C#:

  • Реализация C# в виде компилятора csc.exe включена в состав

.NET Framework (включая .NET Micro Framework, .NET Compact Framework и его реализации под Silverlight и Windows Phone 7);

  • В составе проекта Rotor (Shared Source Common Language Infrastructure) компании Microsoft;

  • Проект Mono включает в себя реализацию C# с открытым исходным кодом;

  • Проект DotGNU также включает компилятор C# с открытым кодом;

  • DotNetAnywhere — ориентированная на встраиваемые системы реализация CLR, поддерживает практически всю спецификацию C# 2.0;




    1. Используемые библиотеки

Для нормализации изображения и выделения контуров, а также доступа к видеопотоку камеры используется библиотека EmguCV.
Emgu CV является кроссплатформенным .Net дополнением для библиотеки OpenCV для обработки изображений. Разработано для работы с
.NET совместимыми языками, такими как C #, VB, VC ++, IronPython и т.д., может быть использовано в Visual Studio, Xamarin, работает с Windows, Linux, Mac OS X, IOS, Android и Windows Phone.
В соответствии с рисунком 16 Emgu CV имеет два слоя:

  • Базовый слой (Слой 1) содержит функции, структуры и перечисления которые напрямую отражены в OpenCV;

  • Второй слой (Слой 2) содержит классы которые дополнены преимуществами платформы .NET [12];

Рисунок 16 - Архитектура EmguCV


OpenCV (англ. Open Source Computer Vision Library, библиотека компьютерного зрения с открытым исходным кодом) — библиотека алгоритмов компьютерного зрения, обработки изображений и численных алгоритмов общего назначения с открытым кодом. Реализована на C/C++, также разрабатывается для Python, Java, Ruby, Matlab, Lua и других языков. Может свободно использоваться в академических и коммерческих целях — распространяется в условиях лицензии BSD [13].
Для распознавания найденных символов используется библиотека tesseract ocr. Решено было использовать данную библиотеку потому что она популярна, бесплатна и есть поддержка русского языка.
Tesseract — свободная компьютерная программа для распознавания текстов, разрабатывавшаяся Hewlett-Packard с середины 1980-х по середину 1990-х, а затем 10 лет «пролежавшая на полке». В августе 2006 г. Google купил её и открыл исходные тексты под лицензией Apache 2.0 для продолжения разработки. В настоящий момент программа уже работает с UTF-8, поддержка языков (включая русский с версии 3.0) осуществляется с помощью дополнительных модулей [14].
Для поиска фрагмента изображения с автомобильным номером используется библиотека openalprnet. Найденное изображение с регистрационным номером автомобиля подвергается дальнейшей обработке разработанной программой с целью определения номера. Данная библиотека еще и распознает сам номер, но делает это не всегда правильно, так как она не рассчитана на русский формат номеров. Эти результаты распознавания проверяются на соответствие шаблону, и дополняют результаты программы.
OpenALPR это библиотека с открытым исходным кодом для автоматического распознавания номерных знаков. Написанная на С++ с привязками к C#, Java, Node.js, и Python. Библиотека анализирует изображения и видеопотоки для идентификации номерных знаков. В результате на выходе выдает изображение с номерным знаком и распознанный номер [15].

  1. Программная реализация

    1. Программа распознавания автомобильных номеров

Главная форма программы распознавания автомобильных номеров в соответствии с рисунком 17, имеет элементы:

      • Кнопка «Старт» для запуска мониторинга парковочных мест;

      • Кнопка «Стоп» для остановки мониторинга парковочных мест;

      • Кнопка «Настройки» открывает форму с настройками программы;

      • Элемент PictureBox в который выводятся кадры из видео;

      • Кнопка «…» для загрузки тестовых примеров автомобильных номеров;

Распознавание номера происходит в классе NumberRecognizer (Приложение A), который в свою очередь использует функции обработки изображений из класса ImageFunctions (Приложение Б), например, функцию бинаризации изображения. Контуров в номере находится больше чем нужно, необходимо удалить лишние и отсортировать оставшиеся в правильном порядке это происходит в классе BoxFunctions (Приложение B). В результате получаем набор изображений с каждым отдельным символом автомобильного номера. Каждый символ передается на распознавание в класс MyTesseract (Приложение Г). После распознавания необходимо проверить получившийся номер, для этого есть класс NumberNormalize (Приложение Д), который кроме проверки может исправить некоторые ошибки распознавания. Например, если первый символ номера распознался как ноль, то очевидно, что это должна быть буква «О». Для подключения к камере используется класс MyCamera (Приложение Ж).


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

Рисунок 17- Программа распознавания номеров
В программе есть возможность выбора источника видеопотока. Можно выбрать в качестве источника видео IP камеру с поддержкой протокола RTSP или можно выбрать USB камеру, подключенную в компьютеру. Форма настроек в соответствии с рисунком 18.имеет следующие поля: IP адрес камеры, порт, логин и пароль.

Рисунок 18 - Форма настроек программы
На используемом компьютере распознавание номера происходит в среднем за 600мс. Проведя анализ затраченных ресурсов были составлены минимальные системные требования к серверу на котором будет работать программа распознавания регистрационных номеров.
Минимальные:
ОС: 64-bit : Win Vista, Win 7, Win 8, Win 10 Процессор: Intel Core 2 duo
Оперативная память: 2 ГБ ОЗУ Место на диске: 200 МБ Доступ в сеть
Требуемое ПО: .NET Framework 4

    1. Программа распознавания свободных мест

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

      • Кнопка «Print Aruco Board» для вывода на печать Aruco меток;

      • Кнопка «Старт» для запуска мониторинга парковочных мест;

      • Кнопка «Стоп» для остановки мониторинга парковочных мест;

      • Кнопка «Настройки» открывает форму с настройками программы;

      • Элемент PictureBox в который выводятся кадры из видео;

Для распознавания меток на изображении используется класс Markers (Приложение Ж), который в свою очередь обновляет состояние места, представленного классом Spot (Приложение И). Дабы исключить
вероятность ошибочного распознавания состояния места результат должен повториться несколько раз, за этим следит класс Spot.

Рисунок 19 - Программа распознавания свободных мест
Чтобы пользователи могли иметь актуальную информацию необходимо чаще обновлять информацию о местах в БД. С другой стороны, слишком частое обновление БД создаст дополнительную нагрузку на СУБД. Поэтому важно было выбрать оптимальный период обновления. Проведя анализ данной проблемы было решено сделать период равным 1 секунде. Компонент таймер с заданным периодом берет информацию из класса Spot и обновляет данные в БД.
Для парковки одной камеры будет недостаточно. Для использования нескольких камер нужно будет запустить несколько экземпляров программы. При выбранном размере метки кодов хватит на 216 (65536) парковочных мест. При необходимости можно увеличить число возможных комбинаций графических меток, но это может негативно казаться на качестве распознавания.
В соответствии с рисунком 20 в окне настроек указывается следующее для сетевой камеры:

      • IP адрес;

      • Порт;

      • Логин;

      • Пароль;

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

Рисунок 20 - Окно настроек
Проанализировав затраты вычислительных ресурсов были составлены минимальные системные требования.
Минимальные:
ОС: 64-bit: Win Vista, Win 7, Win 8, Win 10 Процессор: Intel Core 2 duo
Оперативная память: 2 ГБ ОЗУ Место на диске: 120 МБ Доступ в сеть
Требуемое ПО: .NET Framework 4
ЗАКЛЮЧЕНИЕ
В результате выполнения выпускной квалификационной работы была достигнута поставленная цель и выполнены поставленные задачи:

  • Выполнен обзор существующих аналогов;

  • Произведена настройка видеооборудования;

  • Проведен анализ технологий распознавания номеров;

  • Выполнен анализ технологий мониторинга парковочных мест;

  • Сделан обзор используемого ПО;

  • Разработана система видео-мониторинга парковочного пространства;

  • Разработанная система опробована на макете парковки;

Применяя современные технологии видеоанализа можно сделать парковку более удобной для водителей. Камеры видеонаблюдения можно использовать не только в целях безопасности, но и для определения состояния парковочных мест. В случае возникновения нештатных ситуаций можно своевременно предупредить владельца транспортного средства. Чтобы найти свой автомобиль можно воспользоваться сервисом через мобильное приложение или терминалы. Распознавание номеров позволит службе безопасности следить за тем, кто въезжает и уезжает с парковки. Используя современные технологии видеоанализа и разработанную систему видео-мониторинга парковочного пространства можно вывести парковку на новый уровень и идти в ногу со временем.


СПИСОК ИСПОЛЬЗОВАННЫХ ИСТОЧНИКОВ

  1. Умная парковка [Электронный ресурс] АБС авто режим доступа: http://www.abs-magazine.ru/article/umnaja-parkovka (дата обращения 10.05.2017)

  2. Parkeon [Электронный ресурс] - Режим доступа http://www.parkeon.co.uk (дата обращения 10.05.2017)

  3. Официальный сайт компании Микком [Электронный ресурс] - Режим доступа: http://miccom.ru/products/pm-about/pm1 (дата обращения 10.05.2017)

  4. «Умные парковки» – новый подход к решению проблемы паркинга в городах [Электронный ресурс]: Официальный сайт компании Аксиома Групп - Режим доступа: http://xn--80aehoibjimhm4a0i.xn--p1ai/ (дата обращения 10.05.2017)

  5. Руководство установке IP-камеры видеонаблюдения Cisco Video Surveillance 6000P [Электронный ресурс]: Сайт компании Cisco - Режим доступа:

http://www.cisco.com/assets/global/RU/documentation/6000Phig-rus.pdf (дата обращения 12.05.2017)

  1. Компьютерное зрение [Электронный ресурс]: Habrahabr Режим доступа: https://habrahabr.ru/company/yandex/blog/203136/ (дата обращения 10.05.2017)

  2. Распознавание номеров: от А до 9 [Электронный ресурс]: Habrahabr Режим доступа: https://habrahabr.ru/company/recognitor/blog/221891/ (дата обращения 13.05.2017)

  3. Detection of ArUco Markers [Электронный ресурс]: сайт openCV - Режим доступа:

http://docs.opencv.org/3.1.0/d5/dae/tutorial_aruco_detection.html (дата обращения 13.05.2017)

  1. Visual Studio [Электронный ресурс]: Wikipedia - Режим доступа: https://ru.wikipedia.org/wiki/Microsoft_Visual_Studio (дата обращения 15.05.2017)

  2. Общие сведения о платформе .NET Framework [Электронный ресурс]: Microsoft Режим доступа: https://msdn.microsoft.com/ru- ru/library/zw4w595w(v=vs.110).aspx (дата обращения 15.05.2017)

  3. C Sharp [Электронный ресурс]: Wikipedia Режим доступа: https://ru.wikipedia.org/wiki/C_Sharp (дата обращения 15.05.2017)

  4. Библиотека EmguCV [Электронный ресурс]: EmguCV Режим доступа: http://www.emgu.com/wiki/index.php/Tutorial (дата обращения 16.05.2017)

  5. Библиотека OpenCV [Электронный ресурс] Режим доступа: http://opencv.org

  6. Tesseract OCR [Электронный ресурс] github хостинг - Режим доступа: https://github.com/tesseract-ocr (дата обращения 16.05.2017)

  7. OpenAlpr [Электронный ресурс] Режим доступа: http://doc.openalpr.com/ (дата обращения 16.05.2017)

using Emgu.CV;


using Emgu.CV.CvEnum; using Emgu.CV.Structure; using Emgu.CV.Util; using openalprnet;
using System;
ПРИЛОЖЕНИЕ А
Класс для распознавания номеров

using System.Collections.Generic; using System.Drawing;
using System.Linq;

namespace ALPRV9000


{
class NumberRecognizer
{
public NumberRecognizer()
{ }

private List images_steps = new List();


public List compare_results = new List(); public List getStepsImages()
{ return images_steps; }

private void AddUmatToLog(List images)


{
foreach (var image in images) images_steps.Add(image.Clone().Bitmap);
}

private void AddBitmapToLog(Bitmap image)


{ images_steps.Add(image); }

private void AddBitmapsToLog(List images)


{ images_steps.AddRange(images); }

public List getNumberCar(Bitmap image)


{
images_steps.Clear();
List numberPlate = findNumberPlate(image); if (numberPlate.Any())
Recognize(numberPlate[0]); numberPlate = null;
return numbers;
}

//Mat filteredGray_global;


private void Recognize(Image imageSource)
{
string number = "";
MyTesseract myTesseract = new MyTesseract();

using (Bitmap bitMap = new Bitmap(imageSource))
using (Bitmap ExtendedBitMap = ImageFunctions.ExtendBitmap(bitMap, new Size(bitMap.Width, bitMap.Height + 20), new Point(0, 10), Brushes.White))
using (Mat imageMat = ImageFunctions.BitMapToMat(ExtendedBitMap))//В нужный формат
using (Mat gray = new Mat()) //Серое
{
CvInvoke.CvtColor(imageMat, gray, ColorConversion.Bgr2Gray);
using (Mat grayResized = ImageFunctions.Resize(gray, new Size(600, 150)))
//Изменен размер
using (Mat filteredGray = ImageFunctions.FilterPlate(grayResized))//Контуры using (Mat canny = new Mat())//Контуры
{
//filteredGray_global = filteredGray;//для отладки CvInvoke.Canny(filteredGray, canny, 50, 100, 3, false); using (VectorOfVectorOfPoint contours = new
VectorOfVectorOfPoint())//Контуры
using (Mat hierarchy = new Mat())//Какая то фигня
{
CvInvoke.FindContours(canny, contours, hierarchy, RetrType.List, ChainApproxMethod.ChainApproxSimple);
//int[,] hierachy = CvInvoke.FindContourTree(canny, contours, ChainApproxMethod.ChainApproxSimple);
List boxes = BoxFunctions.GetBoxesFromContours(contours, new Size(10, 10), new Size(80, 100)); //Которбки не меньше указанного размера
//List boxes_sizeFiltered = getNormImagesInContours(boxes, grayResized); //для отладки
List boxes_smartFiltered = BoxFunctions.RemoveRepeatedBoxes(boxes);//Убираем повторения
List boxes_sort = BoxFunctions.SortBoxes(boxes_smartFiltered);//Сортируем в правильном порядке
List plates = ImageFunctions.GetImagesInContours(boxes_sort, filteredGray); //Картинки из контуров
List filteredPlates = ImageFunctions.FilterPlates(plates);
//Отфильтрованные
List resizedFilteredPlates = ImageFunctions.Resize(filteredPlates, new Size(240, 180)); //меняем размер
List segments = ImageFunctions.UmatsToBitmaps(resizedFilteredPlates);
List extendedContours = ImageFunctions.ExtendBitmaps(segments, 40, 40, new Point(20, 20), Brushes.Black);
number = myTesseract.GetNumberFromContours(extendedContours);
//Mat testtest = FilterPlateMat(filteredGray);
//number2 = getNumberFromPlate(testtest);
//AddBitmapToLog(grayResized.Clone().Bitmap);
//AddBitmapToLog((Bitmap)filteredGray.Bitmap.Clone()); AddBitmapToLog(canny.Clone().Bitmap);
//AddUmatToLog(filteredPlates);
//AddUmatToLog(boxes_sizeFiltered); AddBitmapsToLog(extendedContours); myTesseract = null;
boxes = null;
boxes_smartFiltered = null; boxes_sort = null;
plates = null; filteredPlates = null;
resizedFilteredPlates = null;
}
}
}
number = NumberNormalize.getNormalizeNumber(number); if (number.Length==6)
{
numbers.Add(number);
}
}
List numberPlate = new List(); List numbers = new List();
private List findNumberPlate(Bitmap image)
{
numberPlate.Clear(); numbers.Clear();
string config_file = "openalpr.conf"; string runtime_data_dir = "runtime_data";
using (var alpr = new AlprNet("eu", config_file, runtime_data_dir))
{
if (!alpr.IsLoaded())
{
throw(new Exception("Error initializing OpenALPR"));
}
alpr.DefaultRegion = "ru";
AlprResultsNet results = alpr.Recognize(image); foreach (var result in results.Plates)
{
foreach(var topNPlates in result.TopNPlates)
{
string numb = NumberNormalize.getNormalizeNumber(topNPlates.Characters); if (numb.Length == 6)
numbers.Add(numb);
List
points = result.PlatePoints;
Rectangle rect = BoxFunctions.BoundingRectangle(points); points = null;
using (Bitmap cropped = ImageFunctions.CropImage(image, rect)) numberPlate.Add(new Bitmap(cropped));
}
}
results = null;
}
return numberPlate;
}
}
}
ПРИЛОЖЕНИЕ Б
Класс содержащий функции обработки изображений
using Emgu.CV;
using Emgu.CV.CvEnum; using Emgu.CV.Structure; using System;
using System.Collections.Generic; using System.Drawing; namespace ALPRV9000
{
class ImageFunctions
{
public static List ExtendBitmaps(List srcBitmaps, int addWidth, int addHeight, Point point, Brush color)
{
List extendedBitmaps = new List(); foreach (var bitmap in srcBitmaps)
{
extendedBitmaps.Add(ExtendBitmap(
new Bitmap(bitmap), new Size(bitmap.Width + addWidth, bitmap.Height + addHeight), new Point(addWidth / 2, addHeight / 2), Brushes.Black));
}
return extendedBitmaps;
}
public static Bitmap ExtendBitmap(Bitmap srcBitmap, Size newSize, Point point, Brush color)
{
Bitmap newImage = new Bitmap(newSize.Width, newSize.Height, srcBitmap.PixelFormat);
using (Graphics g = Graphics.FromImage(newImage))
{
// fill target image with white color
g.FillRectangle(color, 0, 0, newSize.Width, newSize.Height);
// place source image inside the target image g.DrawImage(srcBitmap, point.X, point.Y);
}
return newImage;
}

public static Mat ExtendMat(Mat srcMat, Size newSize, Point point, Brush color)


{
Bitmap tmp = new Bitmap(srcMat.Bitmap);
Bitmap bitMap = ExtendBitmap(tmp, newSize, point, color);
//tmp = null;
Mat extendedMat = BitMapToMat(bitMap); return extendedMat;
}

public static Mat BitMapToMat(Bitmap bgr_image)


{
Image img1 = new Image(bgr_image);
return img1.Mat;
}

public static Bitmap CropImage(Bitmap img, Rectangle cropArea)


{
try
{
return img.Clone(cropArea, img.PixelFormat);
}
catch (OutOfMemoryException ex)
{
return (Bitmap)img.Clone();
}
}

public static Mat FilterPlate(Mat plate)


{
Mat thresh = new Mat();
CvInvoke.Threshold(plate, thresh, 100, 255, ThresholdType.Otsu); CvInvoke.Erode(thresh, thresh, null, new Point(-1, -1), 1, BorderType.Constant,
CvInvoke.MorphologyDefaultBorderValue);
CvInvoke.Dilate(thresh, thresh, null, new Point(-1, -1), 1, BorderType.Constant, CvInvoke.MorphologyDefaultBorderValue);

return thresh;


}

public static List FilterPlates(List plates)


{
List threshes = new List(); foreach (var plate in plates)
{
UMat thresh = FilterPlate(plate); threshes.Add(thresh.Clone());
}
return threshes;
}

public static UMat FilterPlate(UMat plate)


{
UMat thresh = new UMat();
CvInvoke.Threshold(plate, thresh, 100, 255, ThresholdType.BinaryInv); CvInvoke.Erode(thresh, thresh, null, new Point(-1, -1), 1, BorderType.Constant,
CvInvoke.MorphologyDefaultBorderValue);
CvInvoke.Dilate(thresh, thresh, null, new Point(-1, -1), 1, BorderType.Constant, CvInvoke.MorphologyDefaultBorderValue);

return thresh;


}

public Mat FilterPlateMat(Mat plate)


{
Mat thresh = new Mat();
CvInvoke.Threshold(plate, thresh, 100, 255, ThresholdType.BinaryInv); CvInvoke.Erode(thresh, thresh, null, new Point(-1, -1), 1, BorderType.Constant,
CvInvoke.MorphologyDefaultBorderValue);
CvInvoke.Dilate(thresh, thresh, null, new Point(-1, -1), 1, BorderType.Constant, CvInvoke.MorphologyDefaultBorderValue);

return thresh;


}

public static Mat Resize(Mat source, Size size)


{
Mat dest = new Mat();
double scale = Math.Min((float)size.Width / (float)source.Size.Width, (float)size.Height / (float)source.Size.Height);
Size newSize = new Size((int)Math.Round(source.Size.Width * scale), (int)Math.Round(source.Size.Height * scale));
CvInvoke.Resize(source, dest, newSize, 0, 0, Inter.Cubic); return dest;
}

public static UMat Resize(UMat source, Size size)


{
UMat dest = new UMat();
double scale = Math.Min((float)size.Width / (float)source.Size.Width, (float)size.Height / (float)source.Size.Height);
Size newSize = new Size((int)Math.Round(source.Size.Width * scale), (int)Math.Round(source.Size.Height * scale));
CvInvoke.Resize(source, dest, newSize, 0, 0, Inter.Cubic); return dest;
}

public static List Resize(List sources, Size size)


{
List dest = new List(); foreach (var src in sources)
{
dest.Add(Resize(src, size));
}
return dest;
}

public static List GetImagesInContours(List boxes, Mat from)


{
List imagesMat = new List(); foreach (var box in boxes)
{
float height = Math.Max(box.Size.Height, box.Size.Width); float width = Math.Min(box.Size.Height, box.Size.Width);
//float height = box.Size.Height;
//float width = box.Size.Width; PointF[] destCorners;
if (box.Size.Height > box.Size.Width)
{
destCorners = new PointF[]
{
new PointF(0, height - 1), new PointF(0, 0),
new PointF(width - 1, 0),
new PointF(width - 1, height - 1)};
}
else
{
destCorners = new PointF[]
{
new PointF(width - 1, height - 1), new PointF(0, height - 1),
new PointF(0, 0),
new PointF(width - 1, 0)};
}
PointF[] srcCorners = box.GetVertices();

using (Mat rot = CvInvoke.GetAffineTransform(srcCorners, destCorners)) using (UMat tmp1 = new UMat())


{
CvInvoke.WarpAffine(from, tmp1, rot, Size.Round(new SizeF(width, height))); imagesMat.Add(tmp1.Clone());
}
}
return imagesMat;
}

public static List UmatsToBitmaps(List umats)


{
List bitmaps = new List(); foreach (var umat in umats)
{
bitmaps.Add((Bitmap)umat.Bitmap.Clone());
}
return bitmaps;
}
}
}
ПРИЛОЖЕНИЕ В
Класс, содержащий функции для работы с контурами
using Emgu.CV;
using Emgu.CV.Structure; using Emgu.CV.Util; using System;
using System.Collections.Generic; using System.Drawing;
using System.Linq; using System.Text; namespace ALPRV9000
{
class BoxFunctions
{
public static bool CmpBoxes(RotatedRect box1, RotatedRect box2)
{
bool result = false;//Если не равны

//Левый нижний угол box1


float box1_x1 = box1.Center.X - box1.Size.Width / 2; float box1_y1 = box1.Center.Y - box1.Size.Height / 2;
//Правый верхний угол box1
float box1_x2 = box1.Center.X + box1.Size.Width / 2; float box1_y2 = box1.Center.Y + box1.Size.Height / 2;
//Левый нижний угол box2
float box2_x1 = box2.Center.X - box2.Size.Width / 2; float box2_y1 = box2.Center.Y - box2.Size.Height / 2;
//Правый верхний угол box2
float box2_x2 = box2.Center.X + box2.Size.Width / 2; float box2_y2 = box2.Center.Y + box2.Size.Height / 2; float tolerance_x = box1.Size.Width / 7;
float tolerance_y = box1.Size.Height / 7;
if (box1_x1 > box2_x1 && box1_x2 < box2_x2)
{
if (box1_y1 > box2_y1 && box1_y2 < box2_y2)
{
result = true; //Box1 внутри Box2
}
}
if (box2_x1 > box1_x1 && box2_x2 < box1_x2)
{
if (box2_y1 > box1_y1 && box2_y2 < box1_y2)
{
result = true; //Box2 внутри Box1
}
}
if (box1.Center.X < box2.Center.X + tolerance_x && box1.Center.X > box2.Center.X - tolerance_x)
{
if (box1.Center.Y < box2.Center.Y + tolerance_y && box1.Center.Y > box2.Center.Y
- tolerance_y)
{
if (box1.Size.Height < box2.Size.Height + tolerance_x && box1.Size.Height >
box2.Size.Height - tolerance_x)
{
if (box1.Size.Width < box2.Size.Width + tolerance_y && box1.Size.Width > box2.Size.Width - tolerance_y)
{
result = true;
}
}
}
}
return result;
}
public static List GetBoxesFromContours(VectorOfVectorOfPoint contours, Size minSize, Size maxSize)
{
List boxes = new List(); for (int i = 0; i < contours.Size; i++)
{
RotatedRect box = CvInvoke.MinAreaRect(contours[i]);
if (box.Size.Height < minSize.Height || box.Size.Width < minSize.Width) continue; if (box.Size.Height > maxSize.Height || box.Size.Width > maxSize.Width) continue; boxes.Add(box);
}
return boxes;
}
public static List CheckBoxInArray(List boxes, RotatedRect box)
{
List indexes_remove = new List(); for (int i = 0; i < boxes.Count; i++)
{
if (BoxFunctions.CmpBoxes(boxes[i], box))
{

indexes_remove.Add(i);


}
}
return indexes_remove;
}
public static List RemoveRepeatedBoxes(List boxes)
{
List boxes_result = new List(); List indexes_remove = new List();
for (int i = 0; i < boxes.Count; i++)
{
indexes_remove = CheckBoxInArray(boxes_result, boxes[i]); if (indexes_remove.Count() == 0)
boxes_result.Add(boxes[i]); //Если в массиве нет такого else
{
List temp = new List();
for (int z = 0; z < boxes_result.Count; z++)
{
if (indexes_remove.Contains(z)) continue; temp.Add(boxes_result[z]);
}
boxes_result = new List(temp.ToArray()); boxes_result.Add(boxes[i]); //Если в массиве нет такого
}
}
return boxes_result;
}

public static List SortBoxes(List boxes)


{
List sortBoxes = new List(boxes); for (int i = 0; i < sortBoxes.Count - 2; i++)
{
bool exchange = false;
for (int j = 0; j < sortBoxes.Count - i - 1; j++)
{

if (sortBoxes[j].Center.X > sortBoxes[j + 1].Center.X)


{
RotatedRect tmp = sortBoxes[j]; sortBoxes[j] = sortBoxes[j + 1]; sortBoxes[j + 1] = tmp; exchange = true;
}
}
if (!exchange) break;
}
return sortBoxes;
}

public static Rectangle BoundingRectangle(List


points)
{
var minX = points.Min(p => p.X); var minY = points.Min(p => p.Y); var maxX = points.Max(p => p.X); var maxY = points.Max(p => p.Y); var height = maxY - minY;
var width = maxX - minX; var needWidth = height * 6.5;
return new Rectangle(new Point(minX, minY), new Size(maxX - minX, maxY - minY));
}
}
}

using System;


ПРИЛОЖЕНИЕ Г
Класс оптического распознавания символов

using System.Collections.Generic; using System.Drawing;
using System.Linq; using System.Text; using Tesseract; namespace ALPRV9000
{
class MyTesseract
{
private TesseractEngine _ocr; public MyTesseract() {
_ocr = new TesseractEngine("NumberRecognizer", "rus", EngineMode.TesseractOnly);
_ocr.SetVariable("tessedit_char_whitelist", "АВЕКМНОРСТУХ-1234567890");
}
public string GetNumberFromContours(List segments) { string numbers = "1234567890";
string letters = "АВЕКМНОРСТУХ";
string letters_numbers = letters + "-" + numbers; string number = "";//Тут будет номер
for (int i = 0; i < segments.Count; i++)
{
string text = "";
using (Page page = _ocr.Process(segments[i], PageSegMode.SingleChar))
{
text = page.GetText(); number += text;
}
}
number = number.Replace("\n", ""); number = number.Replace(" ", ""); number = number.ToUpper(); return number;
}
public string GetNumberFromPlate(Bitmap plate) { string number = "";//Тут будет номер
_ocr.SetVariable("tessedit_char_whitelist", "АВЕКМНОРСТУХ-1234567890"); string text = "";
using (Page page = _ocr.Process(plate, PageSegMode.SingleLine))
{
text = page.GetText(); number += text;
}
return number;
}
}
}

using System.Text;


ПРИЛОЖЕНИЕ Д
Класс проверки номера и исправления ошибок

using System.Text.RegularExpressions; namespace ALPRV9000
{
class NumberNormalize
{
public static string getNormalizeNumber(string number)
{
char rus_O = 'О'; char eng_O = 'O';
string rus_chars = "АВЕКМНОРСТУХ"; string eng_chars = "ABEKMHOPCTYX";
string pattern = @"[" + rus_chars + "0][0-9" + rus_O + "][0-9" + rus_O + "][0-9" + rus_O + "][" + rus_chars + "0][" + rus_chars + "0]";
MatchCollection match = Regex.Matches(number, pattern, RegexOptions.IgnoreCase); string pattern2 = @"[" + eng_chars + "0][0-9" + eng_O + "][0-9" + eng_O + "][0-9" +
eng_O + "][" + eng_chars + "0][" + eng_chars + "0]";
MatchCollection match2 = Regex.Matches(number, pattern2, RegexOptions.IgnoreCase); StringBuilder result = new StringBuilder();
if (match.Count > 0) result.Append(match[0].Value);
if (match2.Count > 0)
{
result.Append(match2[0].Value);
for (int i = 0; i < eng_chars.Length; i++)
result = result.Replace(eng_chars[i], rus_chars[i]);
}
if (result.Length == 6)
{
if (result[0] == '0') result[0] = rus_O;
if (result[1] == rus_O) result[1] = '0';
if (result[2] == rus_O) result[2] = '0';
if (result[3] == rus_O) result[3] = '0';
if (result[4] == '0') result[4] = rus_O;
if (result[5] == '0') result[5] = rus_O;
}
return result.ToString();
}
}
}

using Emgu.CV; using System;


ПРИЛОЖЕНИЕ Е
Класс для подключения к видеокамере

using System.Collections.Generic; using System.Diagnostics;
using System.Drawing; using System.Linq;
using System.Runtime.InteropServices; using System.Text;
using System.Threading; namespace Aruco
{
class MyCamera {
Mat _frame = new Mat();
Mat _frameCopy = new Mat(); private VideoCapture _capture = null; private bool _captureInProgress;
bool netCamera = true; public MyCamera() {
netCamera = false;
_capture = new VideoCapture(1);
_capture.ImageGrabbed += ProcessFrame;
}
string connection_string; void tryConnect()
{
_capture = new VideoCapture(connection_string);//Сетевая камера
_capture.ImageGrabbed += ProcessFrame;
}
Thread thread1;
public MyCamera(string ip, int port, string login, string password) { netCamera = true;
thread1 = new Thread(new ThreadStart(tryConnect)); thread1.IsBackground = true;
thread1.Name = "TryConnectThread"; thread1.Start();
string connection_string = "rtsp://" + login + ":" + password + "@" + ip + "/StreamingSetting?version=1.0&action=getRTSPStream&ChannelID=1&ChannelName=Chann el1";
this.connection_string = connection_string;
}
public delegate void GetFrame(Mat bitMap); GetFrame getFrame;
public void setCallBack(GetFrame getFrame)
{
this.getFrame = getFrame;
}
private void ProcessFrame(object sender, EventArgs arg)
{
if (_capture != null && _capture.Ptr != IntPtr.Zero)

{
_capture.Retrieve(_frame, 0); getFrame(_frame);
}
}
bool check(ProcessThreadCollection tc, ProcessThread t)
{
bool result = false;
for (int i = 0; i < tc.Count; i++)
{
if (tc[i].Id == t.Id) { result = true; break;
}
}
return result;
}
public void Start()
{
if(netCamera) thread1.Join(5000);
try
{
_capture.Start();
_captureInProgress = true;
}
catch
{
throw new TimeoutException("Не удалось подключиться к камере");
}
}
public void Stop()
{
if (_capture != null)
{
_captureInProgress = false;
_capture.Pause();
}
}
public bool getCaptureProgress()
{
return _captureInProgress;
}
public void Pause()
{
_captureInProgress = false;
_capture.Pause();
}
}
}

using Emgu.CV;


ПРИЛОЖЕНИЕ Ж
Класс для оптического распознавания маркеров

using Emgu.CV.Aruco; using Emgu.CV.Structure; using Emgu.CV.Util; using System;
using System.Collections.Generic; using System.Drawing;
using System.Drawing.Printing; using System.Linq;
using System.Text;
using System.Threading.Tasks; using System.Windows.Forms; namespace Aruco
{
class Markers
{
public Markers(int markersX, int markersY, int markersSeparation, int markersLength)
{
this.markersX = markersX; this.markersY = markersY;
this.markersSeparation = markersSeparation; this.markersLength = markersLength;
spots = new Spot[markersX * markersY]; for(int i=0; i{
spots[i] = new Spot(i);
}
}
int markersX; int markersY;
int markersSeparation; int markersLength; private Dictionary _dict;
Mat _cameraMatrix = new Mat(); Mat _distCoeffs = new Mat(); Spot[] spots;
private Dictionary ArucoDictionary
{
get
{
if (_dict == null)
{
_dict = new Dictionary(Dictionary.PredefinedDictionaryName.Dict4X4_100);
}
return _dict;
}
}
private GridBoard _gridBoard; private GridBoard ArucoBoard

{
get
{
if (_gridBoard == null)
{
_gridBoard = new GridBoard(markersX, markersY, markersLength, markersSeparation, ArucoDictionary);
}
return _gridBoard;
}
}
void refreshSpots(int[] arr)
{
for(int i=0; i{
bool occupied = true;
for(int j=0; j{
if (spots[i].getId() == arr[j])
{
occupied = false; break;
}
}
spots[i].Occupied(occupied);
}}
public Spot[] GetSpots()
{ return spots; }
Mat rvecs = new Mat(); Mat tvecs = new Mat();
public Mat ProcessFrame(Mat _frame)
{
using (VectorOfInt ids = new VectorOfInt())
using (VectorOfVectorOfPointF corners = new VectorOfVectorOfPointF()) using (VectorOfVectorOfPointF rejected = new VectorOfVectorOfPointF())
{
DetectorParameters p = DetectorParameters.GetDefault(); ArucoInvoke.DetectMarkers(_frame, ArucoDictionary, corners, ids, p, rejected); ArucoInvoke.RefineDetectedMarkers(_frame, ArucoBoard, corners, ids, rejected, null,
null, 10, 3, true, null, p);
refreshSpots(ids.ToArray()); if (ids.Size > 0)
{

0));
ArucoInvoke.DrawDetectedMarkers(_frame, corners, ids, new MCvScalar(0, 255,


if (!_cameraMatrix.IsEmpty && !_distCoeffs.IsEmpty)


{

ArucoInvoke.EstimatePoseSingleMarkers(corners, markersLength,
_cameraMatrix, _distCoeffs, rvecs, tvecs);
for (int i = 0; i < ids.Size; i++)
{
using (Mat rvecMat = rvecs.Row(i))

using (Mat tvecMat = tvecs.Row(i))
using (VectorOfDouble rvec = new VectorOfDouble()) using (VectorOfDouble tvec = new VectorOfDouble())
{
double[] values = new double[3]; rvecMat.CopyTo(values); rvec.Push(values); tvecMat.CopyTo(values); tvec.Push(values);
ArucoInvoke.DrawAxis(_frame, _cameraMatrix, _distCoeffs, rvec, tvec, markersLength * 0.5f);
}
}
}
}
}
return _frame;
}
public void printArucoBoard()
{
Size imageSize = new Size();
int margins = markersSeparation;
int w = markersX * (markersLength + markersSeparation) - markersSeparation + 2 * margins;
int h = markersY * (markersLength + markersSeparation) - markersSeparation + 2 * margins;
imageSize.Width = Math.Max(w, h); imageSize.Height = Math.Max(w, h); int borderBits = 1;
Mat boardImage = new Mat();
ArucoBoard.Draw(imageSize, boardImage, margins, borderBits); bmIm = boardImage.Bitmap;
PrintImage();
}
private void PrintImage()
{
PrintDocument pd = new PrintDocument();
pd.PrintPage += new PrintPageEventHandler(pd_PrintPage); PrintPreviewDialog printPreviewDialog1 = new PrintPreviewDialog(); printPreviewDialog1.Document = pd; printPreviewDialog1.ShowDialog();
}
void pd_PrintPage(object sender, PrintPageEventArgs e)
{
double cmToUnits = 100 / 2.54;
e.Graphics.DrawImage(bmIm, 0, 0, (float)(15 * cmToUnits), (float)(15 * cmToUnits));
}
Image bmIm;
}
}
ПРИЛОЖЕНИЕ И
Класс для хранения информации о местах

namespace Aruco


{
class Spot
{
int id;
bool occupied = false; int counterNewState = 0; public Spot(int id)
{
this.id = id;
}

public bool IsOccupied()


{
return occupied;
}

public int getId()


{
return id;
}

public void Occupied(bool recivedState)


{
if(recivedState != occupied)
{
counterNewState++;
if (counterNewState > 5)
{
occupied = recivedState; counterNewState = 0;
}
}
else
{
counterNewState = 0;
}

}


}
}

Download 1.02 Mb.

Do'stlaringiz bilan baham:
1   2   3   4   5   6   7




Ma'lumotlar bazasi mualliflik huquqi bilan himoyalangan ©fayllar.org 2024
ma'muriyatiga murojaat qiling