// iANPR2.h  - Заголовочный файл iANPR2 2.7
#pragma once
#include <opencv2/opencv.hpp>
#include <vector>

typedef void* iANPR2Object;
typedef void* iANPR2TrajectoryObject;

// Формат строки возвращаемого результата
#define iANPR2_RESULT_NUMBER_FULL		0	// Все символы кроме расширенных, цифр и латинских букв возвращаются, как &0000, где 0000 - код в UTF-16
											// На настоящий момент это относится к двум символам - Б и Г для номеров Беларуси
											// и к иероглифам провинций Китая
#define iANPR2_RESULT_NUMBER_UTF8		1	// Возвращается номер в UTF-8
#define iANPR2_RESULT_NUMBER_1251		2	// Возвращаются номер в Windows-1251
#define iANPR2_RESULT_NUMBER_LATIN		3	// Возвращаются только латинские символы, другие заменяются знаком '?'

// Настройки распознавания
struct iANPR2Setting
{
	float detectConfThresh = 0.25f; // Пороговое значение детектирования (Рекомендуется 0.25) в интервале (0,1)
	int minPlateHeight = 12;        // Минимальная высота номера в пикселях, ниже которой отбрасывается. Рекомендуется 12
	int minPlateWidth = 50;         // Минимальная ширина номера в пикселях, меньше которой отбрасывается. Рекомендуется 50
	std::vector<std::string>
		templateCountries;          // Шаблоны стран	
	bool turnNumber = true;			// Поворот номера, по умолчанию включен
	int memoryNumberFrames = 4;     // Количество кадров в памяти для накапливаемого распознавания
	int memoryNumberRepeat = 2;	    // Количество повторений номера в памяти для накапливаемого распознавания
	int minSymbolsPlate = 6;        // Минимальное количество символов в номере
	int maxSymbolsPlate = 15;       // Максимальное количество символов в номере
	bool mem = false;               // Использовать запомининание в памяти
	bool expandedResult = false;	// Расширенный результат, в возвращаемые номера добавляются символы строк и регионов	
	int typeResultNumberStr =
		iANPR2_RESULT_NUMBER_LATIN;	// Тип возвращаемого результата 
	bool bigSymbols = false;		// Использование больших символов (нужно при распознавании иероглифов)
	float detectConfPerson = 0.25f; // Пороговое значение детектирования для людей можно устанавливать отдельно
	float detectConfVehicle = 0.25f;// Пороговое значение детектирования для транспортных средств можно устанавливать отдельно
};

// Структура, описывающая возвращаемый номер
struct NumberResult
{
	cv::Rect rect;						// Область детектированного номера
	std::vector<std::string> strings;   // строки - варианты номера
	std::vector<std::string> templates; // строки - имена шаблонов
	std::vector<std::string> zones;		// строки - имена зон. Если зона не найдена, то пустая строка
	std::vector<float> confidence;		// вероятности номеров
	float score;						// Вероятность номера при детектировании
};

// Структура, описывающая возвращаемый объект - не номер
struct ObjectResult
{
	cv::Rect rect;						// Область детектированного объекта
	float score;						// Вероятность детектированного объекта
	int classId;						// номер детектированного класса объекта
	int indexNum;						// Индекс номера в изображении, связанного с объектом. -1 - не связан
};

// Структура, описывающая результат в памяти
struct NumberResultMem
{
	std::string numberString;
	std::string numberTemplate;
	std::string numberZone;
};

// Структура, описывающая содержание точки траектории
struct PointTrajectory
{
	cv::Point point;							// Точка в кадре (левый верхний край номера)
	unsigned long weight;						// Вес точки - сколько кадров в этой точке
	long time;									// Время кадра в миллисекундах от инициализации траектории
};

// Результат траектории для одного номера
struct TrajectoryResult
{
	std::vector<PointTrajectory> points;		// Траектория для быстрого возвращения
	std::string strNumber;						// строка номера
	std::string templateNumber;					// шаблон номера		
	std::string zone;							// страна
	unsigned long weights;						// Общий вес траектории
	unsigned long ID;							// ID траектории
	int classId;								// Класс транспортного средства в траектории (-1 - неизвестен)
};

/*
* Возвратить в буфер строку информации о версии
*/
extern "C" bool iANPR2Version(char* outBuf, int sizeBuf);


/* 
* Инициализация объекта iANPR2
* Агументы:
*   configFile - конфигурационный json файл;
*   license - строка лицензии;
*   error - вовзвращаемая ошибка
* Возвращает объект iANPR2Object
*/
extern "C" iANPR2Object iANPR2Init(char* configFile, char*license, int* error);

/*
* Инициализация объекта iANPR2
* Агументы:
*   detectionModelPath - путь до модели детектирования;
*   batchSize - размер пакета модели детектирования;
*   symbolsDetectModelPath - путь до модели детектирования символов;
*   classificationModelPath - путь до модели классификации символов;
*   classificationModelBPath - путь до большой модели классификации символов (необязательно);
*   plateTemplatesStringInJSON - буфер, содержащий JSON шаблонов номеров;
*   license - строка лицензии;
*   error - вовзвращаемая ошибка
* Возвращает объект iANPR2Object
*/

extern "C" iANPR2Object iANPR2Init2(char* detectionModelPath, int batchSize, char* symbolsDetectModelPath, char* classificationModelPath,
	char* classificationModelBPath, char* plateTemplatesStringInJSON, char* license, int* error);

/* 
* Удаление объекта iANPR2
* Агументы:
*   object - ссылка на iANPR2Object
*/
extern "C" void iANPR2Release(iANPR2Object* object);

/* 
* Удаление объекта iANPR2 - вариант 2
* Агументы:
*   object - iANPR2Object
* Возвращает true, если удачно. False - при ошибке
*/
extern "C" bool iANPR2ReleaseP(iANPR2Object object);

/* 
* Установить настройки распознавания
* Агументы:
*   object - iANPR2Object;
*   settings - заполненная структура iANPR2Setting
* Возвращает true, если удачно. False - при ошибке
*/
extern "C" bool iANPR2Settings(iANPR2Object object, iANPR2Setting settings);

/* 
* Установить настройки распознавания с помощью строки JSON
* Агументы:
*   object - iANPR2Object;
*   json - заполненная структура iANPR2Setting, представленная строкой JSON
* Возвращает true, если удачно. False - при ошибке
*/
extern "C" bool iANPR2SettingsJSON(iANPR2Object object, char* json);

/* 
* Передать пакет изображений на распознавание
* Агументы:
*   object - iANPR2Object;
*   images - вектор изображений
* Возвращает 0, если удачно. Иначе - код ошибки.
*/
extern "C" int anpr2PLate(iANPR2Object object, std::vector<cv::Mat> images);

/* 
* Передать пакет изображений на распознавание только первого шага
* Агументы:
*   object - iANPR2Object;
*   images - вектор изображений
* Возвращает 0, если удачно. Иначе - код ошибки.
*/
extern "C" int anpr2FirstStep(iANPR2Object object, std::vector<cv::Mat> images);

/*
* Передать пакет изображений на распознавание только второго шага
* Агументы:
*   object - iANPR2Object;
*   images - вектор изображений
* Возвращает 0, если удачно. Иначе - код ошибки.
*/
extern "C" int anpr2SecondStep(iANPR2Object object, std::vector<cv::Mat> images);


/* 
* Добавить закодированное изображение - массив байт BMP, JPEG, PNG или TIFF
* Агументы:
*   object - iANPR2Object;
*   imageBytes - массив байт, представляющий формат BMP, JPEG, PNG или TIFF;
*   sizeImage - размер массива
* Возвращает 0, если удачно. Иначе - код ошибки.
*/
extern "C" int anpr2AddImage(iANPR2Object object, const char* imageBytes, long sizeImage);

/* 
* Распознать добавленные anpr2AddImage изображения
* Агументы:
*   object - iANPR2Object
* Возвращает 0, если удачно. Иначе - код ошибки.
*/
extern "C" int anpr2inference(iANPR2Object object);

/* 
* Распознать только первый шаг добавленных anpr2AddImage изображений
* Агументы:
*   object - iANPR2Object
* Возвращает 0, если удачно. Иначе - код ошибки.
*/
extern "C" int anpr2inferenceFirstStep(iANPR2Object object);

/*
* Распознать только второй шаг добавленных anpr2AddImage изображений
* Агументы:
*   object - iANPR2Object
* Возвращает 0, если удачно. Иначе - код ошибки.
*/
extern "C" int anpr2inferenceSecondStep(iANPR2Object object);

/* 
* Получить результат распознавания
* Агументы:
*   object - iANPR2Object
* Возвращает вектор результатов NumberResult для каждого изображения.
*/
std::vector<std::vector<NumberResult>> anpr2GetResult(iANPR2Object object);

/* 
* Получить результат распознавания дополнительных объектов
* Агументы:
*   object - iANPR2Object
* Возвращает вектор результатов ObjectResult для каждого изображения.
*/
std::vector<std::vector<ObjectResult>> anpr2GetAddResult(iANPR2Object object);

/* 
* Получить результат распознавания в формате JSON
* Агументы:
*   object - iANPR2Object
*   outBuf - выходной буфера для JSON;
*   sizeBuf - размер выходного буфера.
* Возвращает 0 и результат распознавания в формате JSON или пустую строку если возникла ошибка или ничего не нашлось. - 1
* если object пустой, и ошибку IA_OUTJSONBUFFERSMALL - если выходной буфер мал
*/
extern "C" int anpr2GetResultJSON(iANPR2Object object, char* outBuf,int sizeBuf);

/*
* Получить дополнительный результат распознавания в формате JSON
* Агументы:
*   object - iANPR2Object
*   outBuf - выходной буфера для JSON;
*   sizeBuf - размер выходного буфера.
* Возвращает 0 и результат распознавания в формате JSON или пустую строку если возникла ошибка или ничего не нашлось. - 1
* если object пустой, и ошибку IA_OUTJSONBUFFERSMALL - если выходной буфер мал
*/
extern "C" int anpr2GetAddResultJSON(iANPR2Object object, char* outBuf, int sizeBuf);

/* 
* Получить результат распознавания в памяти
* Агументы:
*   object - iANPR2Object;
* Возвращает вектор результатов NumberResultMem для каждого изображения.
*/
std::vector<std::vector<NumberResultMem>> anpr2GetResultMem(iANPR2Object object);

/* 
* Получить результат распознавания в памяти в формате JSON
* Агументы:
*   object - iANPR2Object
*   outBuf - выходной буфера для JSON;
*   sizeBuf - размер выходного буфера.
* Возвращает 0 и результат распознавания в формате JSON или пустую строку если возникла ошибка или ничего не нашлось. - 1
* если object пустой, и ошибку IA_OUTJSONBUFFERSMALL - если выходной буфер мал
*/
extern "C" int anpr2GetResultMemJSON(iANPR2Object object, char* outBuf,int sizeBuf);

/*
* Создание объекта для обработки траекторий
* Аргументы:
*   widthImage - ширина изображения в видеопотоке
*   heightImage - высота изображения в видеопотоке
*   tLimitTime - время до устаревания (в миллисекундах), например 10000
*   tLimitFrames - количество кадров до устаревания, например 100
*   typeSpeed - тип при вычислении скорости. 0 - по времени, 1 - по кадру
*/
extern "C" iANPR2TrajectoryObject iANPR2Trajectory(int widthImage, int heightImage, int tLimitTime, int tLimitFrames, int typeSpeed);

/* 
* Удаление объекта траектории
* Агументы:
*   object - iANPR2TrajectoryObject
* Возвращает true, если удачно. False - при ошибке
*/
extern "C" bool iANPR2TrajectoryRelease(iANPR2TrajectoryObject object);

/* 
* Добавление результата распознавания кадра в траекторию
* Агументы:
*   object - iANPR2TrajectoryObject
*   numbers - распознанные номера
*   objects - распознанные дополнительные объекты
* Возвращает true, если удачно. False - при ошибке
*/
bool iANPR2TrajectoryProcess(iANPR2TrajectoryObject object, std::vector<NumberResult> numbers, 
	std::vector<ObjectResult> objects);

/*
* Добавление результата распознавания кадра в траекторию путем строк JSON
* Агументы:
*   object - iANPR2TrajectoryObject
*   jsonNumbers - распознанные номера в формате JSON, возвращенные anpr2GetResultJSON
*   jsonObjects - распознанные дополнительные объекты в формате JSON, возврашенные anpr2GetAddResultJSON
* Возвращает true, если удачно. False - при ошибке
*/
extern "C" bool iANPR2TrajectoryProcessJSON(iANPR2TrajectoryObject object, char* jsonNumbers, char* jsonObjects);

/* 
* Получение текущих траекторий
* Агументы:
*   object - iANPR2TrajectoryObject
* Возвращает текущие траектории
*/
std::vector<TrajectoryResult> iANPR2TrajectoryGetResult(iANPR2TrajectoryObject object);

/*
* Получение текущих траекторий в формате JSON
* Агументы:
*   object - iANPR2TrajectoryObject
*   outBuf - выходной буфера для JSON;
*   sizeBuf - размер выходного буфера.
* Возвращает 0 и результат распознавания в формате JSON или пустую строку если возникла ошибка или ничего не нашлось. - 1
* если object пустой, и ошибку IA_OUTJSONBUFFERSMALL - если выходной буфер мал
*/
extern "C" int iANPR2TrajectoryGetResultJSON(iANPR2TrajectoryObject object, char* outBuf, int sizeBuf);

/*
* Создать линии пересечения для траектории
* На  самом деле линия состоит из двух линий - line1 и line2
* и пересечение фиксируется только тогда, когда пересекаются обе(сделано для исключения ложных срабатываний.
* Аргументы:
*   object - iANPR2TrajectoryObject
*   line1X1 - X координата 1 точки 1 линии
*   line1Y1 - Y координата 1 точки 1 линии
*   line1X2 - X координата 2 точки 1 линии
*   line1Y2 - Y координата 2 точки 1 линии
*   line2X1 - X координата 1 точки 2 линии
*   line2Y1 - Y координата 1 точки 2 линии
*   line2X2 - X координата 2 точки 2 линии
*   line2Y2 - Y координата 2 точки 2 линии
* Возвращает 0 или ошибку.
*/
extern "C" int iANPR2CreateLineIntersection(iANPR2TrajectoryObject object,
	int line1X1, int line1Y1, int line1X2, int line1Y2,
	int line2X1, int line2Y1, int line2X2, int line2Y2);

/*
* Узнать есть ли пересечение линии для конкретного индекса траектории
* Общее количество траекторий и сами траектории берутся из iANPR2TrajectoryGetResult или iANPR2TrajectoryGetResultJSON
* Аргументы:
*   object - iANPR2TrajectoryObject
*   indexTr - индекс траектории
* Возвращает  0 - не пересекло, 1 - пересек сверху-вниз, 2 - снизу вверх, -1 или пустой объект или неправильный индекс
*/
extern "C" int iANPR2GetLineIntersection(iANPR2TrajectoryObject object, int indexTr);

/*
* Установить индекс потока для номеров в памяти
* Аргументы:
*   object - iANPR2Object
*   indexStream - индекс потока
* Возвращает  0 или номер ошибки.
*/
extern "C" int anpr2SetMemStream(iANPR2Object object, int indexStream);