iANPR2 — SDK для распознавания автомобильных номеров. Быстрое развертывание
Что такое iANPR2
iANPR 2 – это комплект средств разработки для распознавания автомобильных номеров второго поколения. Изначально разрабатывалась для возможности использования GPU карт NVIDIA, но поддерживает и работу на CPU.
Достоинства по сравнению с iANPR1:
- значительно более высокое качество распознавание;
- поддерживаются все новые номера России;
- возможность запуска на GPU с использованием TensorRT;
- может распознавать любые однострочные и двухстрочные номера с латинскими символами;
- одновременное распознавание номеров разных стран не приводит к потере качества и замедлению распознавания.
Недостатки по сравнению с iANPR1:
- если в iANPR1 выбрать один тип номеров распознавания, например базовый шаблон российских номеров, то скорость распознавания на CPU будет прилично выше.
Однако при использовании большого количества шаблонов (типов номеров) скорость iANPR1 существенно снижается, и если выбрать несколько стран, то станет медленнее. Да и разработка iANPR1 завершена, а iANPR2 нет. Т.е. будет продолжаться оптимизация библиотеки в том числе и с целью улучшения быстродействия.
Типы версий и удобство развертывания
На настоящий момент в версии 2.1 поддерживаются следующие варианты:
- iANPR2 TRT WINDOWS - TensorRT версия для карт NVIDIA под Windows;
- iANPR2 TRT LINUX - TensorRT версия для карт NVIDIA под Linux;
- iANPR2 CPU WINDOWS - CPU версия для Windows;
- iANPR2 CPU LINUX - CPU версия для LINUX.
При этом подключение во всех случаях одинаковое - используется один и тот же заголовочный файл, но разные библиотеки. Функции библиотеки остаются одинаковыми во всех случаях.
Удобство развертывания состоит в том, что библиотека предоставляется в виде динамической библиотеки с функциями stdcall, что позволяет легко подключить библиотеки практически из любого языка программирования. Вместе с библиотекой идут примеры подключения для C++ и Python.
Вызов в C++
Все примеры работы находятся в одном файле ianpr2test.cpp, где представлены следующие варианты запуска примера:
- распознавание одного изображения - текст распознанных номеров выводится в консоль и на изображение;
- распознавания видеофайла с отображением результата распознавания в окне;
- тесты производительности для одного и параллельных объектов;
- возможность распознавания каталога изображений.
Пример написания функции распознавания одного изображения:
#include "../../include/iANPR2.h"
#include "../../include/iANPR2Errors.h"
void test1Image(const char* cfgname, string name, char* license)
{
// Инициализация iANPR2
int error;
iANPR2Object ia2 = iANPR2Init((char*)cfgname, license,&error);
if (ia2 == NULL || error != int(IANPR2::iANPR2Errors::IA_OK))
{
std::cout << "Cann't init iANPR2Object! Error = " << error << " \n";
return;
}
// Установка настроек
iANPR2Setting settings{ 0.25, 12, 60,{"ru"},false };
iANPR2Settings(ia2, settings);
// Загрузка файла в изображение OpenCV
std::vector <cv::Mat> imgs;
imgs.push_back(cv::imread(name));
// Вызов распознавания изображения
int result = anpr2PLate(ia2, imgs);
if (result != int(IANPR2::iANPR2Errors::IA_OK))
std::cout << "Inference problem! Error = " << result << " \n";
// Получение результатов и вывод их в консоль и изображения (функция drawPlate есть в примере)
vector<vector<NumberResult>> numbers = anpr2GetResult(ia2);
if (!numbers.empty())
for (auto number : numbers[0])
if (!number.strings.empty())
std::cout << number.strings[0] << "\n";
for (int k = 0; k < numbers.size(); k++)
{
drawPlate(imgs[k], numbers[k], name+ "_out.png");
}
// Удаление iANPR2
iANPR2Release(&ia2);
}
На вход функции передаются:
- cfgname - имя конфигурационного файла;
- name - имя графического файла, подлежащего распознаванию;
- license - текст лицензии.
При реальном создании программы конфигурационный файл и текст лицензии передаются в библиотеку один раз - при инициализации объекта iANPR2Object.
Сам конфигурационный файл имеет следующий вид:
{
"versionconfig":2,
"detectionmodelpath": "data/20x/platedetection.engine",
"batchSize": 1,
"classificationmodelpath": "data/20x/classification.engine",
"symbolsdetectmodelpath": "data/20x/symbolsmodel.engine",
"templatesfile": "data/platetemplates.json"
}
Где модели могут быть как движками TensorRT (TRT версия), так и моделями для CPU.
Последовательность действий:
- iANPR2Init - инициализация объекта (объектов может быть несколько, но в версии 2.1 для CPU неэффективно);
- iANPR2Settings - загрузка настроек, важным для номеров РФ нужно указать "ru" шаблон, что позволит немного повысить качество распознавания и позволит отличать цифру 0 от буквы О;
- anpr2PLate - передача вектора изображений (при движке TensorRT детектирования номеров рассчитанном на несколько изображений в векторе будет несколько изображений, иначе одно);
- anpr2GetResult - получение результатов распознавания;
- iANPR2Release - удаление объекта.
Естественно, что в реальной программе инициализация и удаление объекта будут осуществляться один раз, а функции распознавания и получения результатов повторяться.
Вызов в Python
Для упрощения вызова из Python вместе с библиотекой поставляется файл ianpr2class.py, где представлен класс для работы с iANPR2, в котором подключаются нужные функции:
# void* iANPR2Init(char* configFile, char*license, int* error);
self.iANPR2Init = self.lib.iANPR2Init
self.iANPR2Init.restype = ctypes.c_void_p
self.iANPR2Init.argtypes = (ctypes.c_char_p,ctypes.c_char_p,ctypes.POINTER(ctypes.c_int),)
# void iANPR2Release(iANPR2Object* object);
self.iANPR2ReleaseP = self.lib.iANPR2ReleaseP
self.iANPR2ReleaseP.restype = ctypes.c_bool
self.iANPR2ReleaseP.argtypes = (ctypes.c_void_p,)
# bool iANPR2SettingsJSON(iANPR2Object object, char* json);
self.iANPR2SettingsJSON = self.lib.iANPR2SettingsJSON
self.iANPR2SettingsJSON.restype = ctypes.c_bool
self.iANPR2SettingsJSON.argtypes = (ctypes.c_void_p,ctypes.c_char_p,)
# int anpr2AddImage(iANPR2Object object, const char* image_bytes, long size_image);
self.anpr2AddImage = self.lib.anpr2AddImage
self.anpr2AddImage.restype = ctypes.c_int
self.anpr2AddImage.argtypes = (ctypes.c_void_p,ctypes.c_char_p,ctypes.c_long,)
# int anpr2inference(iANPR2Object object);
self.anpr2inference = self.lib.anpr2inference
self.anpr2inference.restype = ctypes.c_int
self.anpr2inference.argtypes = (ctypes.c_void_p,)
# int anpr2GetResultJSON(iANPR2Object object, char* outBuf, int sizeBu);
self.anpr2GetResultJSON = self.lib.anpr2GetResultJSON
self.anpr2GetResultJSON.restype = ctypes.c_int
self.anpr2GetResultJSON.argtypes = (ctypes.c_void_p,ctypes.c_char_p,ctypes.c_int,)
#int anpr2GetResultMemJSON(iANPR2Object object, char* outBuf, int sizeBu);
self.anpr2GetResultMemJSON = self.lib.anpr2GetResultMemJSON
self.anpr2GetResultMemJSON.restype = ctypes.c_int
self.anpr2GetResultMemJSON.argtypes = (ctypes.c_void_p,ctypes.c_char_p,ctypes.c_int,)
Главные отличия в работе по сравнению с C++:
- настройки передаются через JSON;
- используется двухэтапное распознавание, где сначала с помощью функции anpr2AddImage изображение (в формате графического файла BMP, JPEG, PNG или TIFF) добавляется в буфер, а после вызывается функция anpr2inference;
- результаты распознавания получаются в формате JSON в виде текстовой строки - anpr2GetResultJSON.
Ну и в самом классе реализованы дополнительные функции для упрощения работы. Пример написания функции для распознавания одного изображения на Python:
import cv2
import numpy as np
import json
import ianpr2class as ia2
def iANPR2Recognition(config, mode, param1):
ianpr2 = ia2.iANPR2( 'D:\\ianpr2\\ianpr2CPP\\bin\\ianpr2CPU.dll' )
# Настройки
settings = {
"detectConfThresh":0.25,
"minPlateHeight": 12,
"minPlateWidth": 60,
"templateCountries":[
"ru"
],
"parallelCPUfunc":0, # 0 or 1
"memoryNumberFrames":8,
"memoryNumberRepeat":4,
"minSymbolsPlate": 6,
"maxSymbolsPlate": 15,
"mem":param2, # 0 or 1
}
# Читаем лицензию
lic = ""
with open("lic2.key", "r") as f:
# итерация по строкам
for line in f:
lic = line.strip()
break
# Инициализация объекта
if ianpr2.initiANPR2Object(config,lic):
if ianpr2.setSettings(settings):
# Объект готов принимать изображения на распознавание
if mode == 0:
# 1 изображение в пакете
img = cv2.imread(param1)
if ianpr2.putImage(img):
if ianpr2.inference():
s = ianpr2.getResult()
print(s) # JSON в строке
if (len(s) > 1):
d = json.loads(s)
if d.get("images"):
drawImage(img,"out.png",d["images"][0])
Последовательность действий:
- инициализация вспомогательного класса путем передачи ссылки на библиотеку ia2.iANPR2( 'D:\\ianpr2\\ianpr2CPP\\bin\\ianpr2CPU.dll' );
- заполнение словаря настроек settings;
- показан пример чтение лицензии из файла (это просто текстовая строка);
- initiANPR2Object - инициализация объекта;
- setSettings - передача настроек;
- putImage - передача изображения в буфер (putImage в классе вызывает anpr2AddImage);
- inference - запуск распознавания;
- getResult - получение результата - строка JSON.
Пример результата распознавания:
{
"images":[
[
{
"x":233,
"y":286,
"width":192,
"height":54,
"strings":[
"Y758CC56"
],
"templates":[
"base_1"
],
"confidence":[
0.983965
],
"score":0.889966
}
]
]
}
Установка в Windows
Для Windows какой-либо установки не требуется, так как все dll идут в комплекте. Однако, если вы хотите подключать через C++, то вам необходимо будет использовать нужную версию OpenCV, чтобы передавался правильный cv::Mat.
В С++ необходимо подключать lib файл, в Python - просто воспользоваться классом.
Установка в Linux
Для TRT версии:
- установка CUDA;
- установка OpenCV;
- установка TensorRT.
Для CPU версии:
- установка OpenCV;
- установка OpenVINO.
Подробные сведения об установке указаны в документации к iANPR2.
Качество распознавания
Выборки для тестирования:
- RUS1 – выборка для распознавания номеров России, которая изначально использовалась для тестирования iANPR1;
- KAZ1 – выборка для распознавания номеров Казахстана, которая изначально использовалась для тестирования iANPR1;
- RUS2 – вторая выборка для распознавания номеров России (ее не было при разработке iANPR1).
Выборки не самые простые, в них включены номера, которые очень сложно рассмотреть глазу.
В таблице ниже представлены результаты тестирования. Достоверность результатов вычисляется по следующему показателю:
D = T/A
где T – правильно распознанные номера (строка номера полностью совпадает), A – все номера.
|
iANPR 1.8 |
iANPR 2.12 TensorRT |
iANPR 2.11 CPU |
RUS1 |
0.614 |
0.783 |
0.766 |
KAZ1 |
0.479 |
0.794* |
0.773* |
RUS2 |
0.547 |
0.858 |
0.846 |
* - результаты тестирования не учитывали различия 0 (ноль) и O (буква).
При этом результаты ложных срабатываний – обнаружение номера там, где его не было – не учитывались. Но в версии iANPR 2 они существенно ниже, чем в iANPR 1.8.
Как видно из результатов тестов, качество распознавания улучшено значительно. Между тем даже iANPR1 вполне годилось для распознавания при суммировании результатов с нескольких кадров.
Быстродействие iANPR2
Быстродействие в расчете на одно изображение
CPU версия:
- i7-6700K 4.0ГГц 4 ядерный – 0.054с;
- Intel Xeon Processor (Cascadelake) 1.4 ГГц 8 ядерный – 0.046 с.
TRT версия:
- 1 объект i7-6700K 4.0ГГц 4 ядра и RTX 2080 Super batchSize = 1 - 0.0095c;
- 4 объекта i7-6700K 4.0ГГц 4 ядра и RTX 2080 Super batchSize = 1 - 0.0061с;
- 4 объекта i7-6700K 4.0ГГц 4 ядра и RTX 2080 Super batchSize = 4 - 0.0057с.
При этом для TRT версии пока важна частота процессора, так как часть операций выполняется на CPU.
Работы по улучшению быстродействия продолжаются.
Некоторые результаты распознавания
Ссылки
Страничка библиотеки: https://intbusoft.com/ianpr2/
Документация: https://intbusoft.com/doc/iANPR2.pdf