Начало работы
Processing Block API (API процессинг-блоков) является масштабируемым интерфейсом, замещающим существующее Legacy API для более легкой интеграции возможностей Face SDK в ваше приложение.
Основные возможности
- Объединение многочисленных компонентов в единую интеграцию
- Простота и легкость изучения
- Быстрое внедрение
- Долгосрочная поддержка и обновления
Требования
- Операционная система Windows x86 64-bit или Linux x86 64-bit.
- Установлен пакет Face SDK windows_x86_64 или linux_x86_64 (см. Начало работы).
Context-контейнер
Ключевой концепцией API процессинг-блоков является использование контейнеров Context.
Context — это гетерогенный контейнер, состоящий из набора иерархически организованных данных, представленных как пары ключ-значение. Ближайший аналог Context — объект JSON. Каждый объект Context может содержать: скалярный объект (integer, real, boolean, string), указатель на область памяти, массив объектов Context, ассоциативный контейнер пар <string, Context> с неограниченной вложенностью.
Как создать и использовать Context-контейнер
Создайте Context-контейнер:
- C++
- Python
- Flutter
- C#
- Java
auto array_elem0 = service->createContext();
array_elem0 = service.createContext({})
Context array_elem0 = service.createContext({});
Context array_elem0 = service.CreateContext(new());
Context array_elem0 = service.createContext();
Общий набор операций с Context:
создание ассоциативного контейнера по ключу
["key"]
на пустом контейнере Context:- C++
- Python
- Flutter
- C#
- Java
array_elem0["name"] = "Julius Zeleny"; // передать string
array_elem0["phone"] = 11111111111l; // передать integer (long)
array_elem0["social_score"] = 0.999; // передать double
array_elem0["verified"] = true; // передать boolarray_elem0["name"] = "Julius Zeleny" # передать string
array_elem0["phone"] = 11111111111 # передать integer
array_elem0["social_score"] = 0.999 # передать double
array_elem0["verified"] = True # передать boolarray_elem0["name"] = "Julius Zeleny"; // передать string
array_elem0["phone"] = 11111111111; // передать integer
array_elem0["social_score"] = 0.999; // передать double
array_elem0["verified"] = true; // передать boolarray_elem0["name"] = "Julius Zeleny"; // передать string
array_elem0["phone"] = 11111111111L; // передать integer
array_elem0["social_score"] = 0.999; // передать double
array_elem0["verified"] = true; // передать boolarray_elem0.get("name").setString("Julius Zeleny"); // передать string
array_elem0.get("phone").setLong(11111111111l); // передать integer
array_elem0.get("social_score").setDouble(0.99); // передать double
array_elem0.get("verified").setBool(true); // передать boolгеттеры:
- C++
- Python
- Flutter
- C#
- Java
ASSERT_EQ( array_elem0["name"].getString(), "Julius Zeleny" );
ASSERT_EQ( array_elem0["phone"].getLong(), 11111111111l );
ASSERT_EQ( array_elem0["social_score"].getDouble(), 0.999 );
ASSERT_EQ( array_elem0["verified"].getBool(), true );assert array_elem0["name"].get_value(), "Julius Zeleny"
assert array_elem0["phone"].get_value() == 11111111111
assert array_elem0["social_score"].get_value() == 0.999
assert array_elem0["verified"].get_value() == Trueassert (array_elem0["name"].get_value() == "Julius Zeleny");
assert (array_elem0["phone"].get_value() == 11111111111);
assert (array_elem0["social_score"].get_value() == 0.999);
assert (array_elem0["verified"].get_value() == true);Debug.Assert(array_elem0["name"].GetString() == "Julius Zeleny");
Debug.Assert(array_elem0["phone"].GetLong() == 11111111111L);
Debug.Assert(array_elem0["social_score"].GetDouble() == 0.999);
Debug.Assert(array_elem0["verified"].GetBool() == true);assertTrue(array_elem0.get("name").getString().equals("Julius Zeleny"));
assertTrue(array_elem0.get("phone").getLong() == 11111111111l);
assertTrue(array_elem0.get("social_score").getDouble() == 0.99);
assertTrue(array_elem0.get("verified").getBool() == true);создание массива вызовом метода
push_back
на пустом контейнере Context:- C++
- Python
- Flutter
- C#
- Java
auto array == service->createContext();
array.push_back(array_elem0);array = service.create_context([])
array.push_back(array_elem0)Context array = service.createContext([]);
array.pushBack(array_elem0);Context array == service->CreateContext(new());
array.PushBack(array_elem0);Context array = service.createContext();
array.pushBack(array_elem0);итерации по массиву:
- C++
- Python
- Flutter
- C#
- Java
// получить значение по индексу
ASSERT_EQ( array[0]["phone"].getLong(), 11111111111l );
// выполнить итерацию с индексом
size_t array_sz = array.size();
for(size_t i = 0; i < array_sz; ++i)
array[i]["phone"];
// или с итераторами
for(auto iter = array.begin(); iter != array.end(); ++iter)
(*iter)["phone"]; // возвращается вложенный Context
// или с foreach
for(auto val : array)
val["phone"];# получить значение по индексу
assert array[0]["phone"].get_value() == 11111111111
# выполнить итерацию с индексом
for i in range(len(array)):
array[i]["phone"]
# или с итераторами
for elem in array:
elem["phone"]// получить значение по индексу
assert (array[0]["phone"].get_value() == 11111111111);
// выполнить итерацию с индексом
for (int i = 0; i < array.len(); i++)
array[i]["phone"];// получить значение по индексу
Debug.Assert(array[0]["phone"].GetLong() == 11111111111L);
// выполнить итерацию с индексом
for (long i = 0; i < array.Length(); i++)
array[i]["phone"];// получить значение по индексу
assertTrue(array.get(0).get("phone").getLong() == 11111111111l);
// выполнить итерацию с индексом
for (int i = 0; i < array.size(); i++)
array.get(i).get("phone");операции со вложенными ассоциативными контейнерами:
- C++
- Python
- Flutter
- C#
- Java
auto full = service->createContext();
full["friends"] = std::move(array); // использование семантики перемещения без копирования
// доступ к вложенному объекту
ASSERT_EQ( full["friends"][0]["social_score"].getDouble(), 0.999 );
// перебор значений ассоциативного контейнера
for(auto iter = full.begin(); iter != full.end(); ++iter) {
iter.key(); // получить значение ключа из итератора
(*iter)[0]["social_score"].getDouble(); // получить значение
}
// с foreach
for(auto val : full)
val[0]["social_score"].getDouble();full = service.create_context({})
full["friends"] = array.to_dict()
# доступ к вложенному объекту
assert full["friends"][0]["social_score"].get_value() == 0.999
# перебор значений ассоциативного контейнера
for key in full.keys():
full[key][0]["social_score"].get_value()Context full = service.createContext({});
full["friends"] = array.toMap();
// доступ к вложенному объекту
assert (full["friends"][0]["social_score"].get_value() == 0.999);
// перебор значений ассоциативного контейнера
for (var key in full.getKeys())
full[key][0]["social_score"].get_value();Context full = service.createContext(new());
full["friends"] = array;
// доступ к вложенному объекту
Debug.Assert(full["friends"][0]["social_score"].GetDouble() == 0.999);
// перебор значений ассоциативного контейнера
foreach (String key in full.GetKeys())
full[key][0]["social_score"].GetDouble();Context full = service.createContext();
full.get("friends").setContext(array);
// доступ к вложенному объекту
assertTrue(full.get("friends").get(0).get("social_score").getDouble() == 0.999);
// перебор значений ассоциативного контейнера
for (String key : full.getKeys())
{
full.get(key).get(0).get("social_score").getDouble();
}другие удобные методы Context:
- C++
- Python
- Flutter
- C#
- Java
void clear();
bool contains(const std::string& key); // для ассоциативного контейнера
Context operator[](size_t index); // для последовательного массива, элемент с указанием доступа и проверкой границ
Context operator[](const std::string& key); // для ассоциативного контейнера, доступ или вставка данных
Context at(const std::string& key); // для ассоциативного контейнера, с проверкой границ
size_t size(); // возвращается число элементов контейнера
bool isNone(); // проверка на пустоту
bool isArray(); // проверка на последовательный массив
bool isObject(); // проверка на ассоциативный контейнер
bool isLong(), isDouble(), isString(), isBool(); // проверка на содержание скалярного типа данныхdef to_dict(self) -> dict # преобразует context в словарь
def is_none(self) -> bool # проверка на пустоту
def is_array(self) -> bool # проверка на последовательный массив
def is_object(self) -> bool # проверка на ассоциативный контейнер
def is_long, is_double, is_string, is_bool -> bool # проверка на содержание скалярного типа данныхContext operator[](int index) // для последовательного массива, элемент с указанием доступа и проверкой границ
Context operator[](String key) // для ассоциативного контейнера, доступ или вставка данных
int len() // возвращается число элементов контейнера
bool is_none() // проверка на пустоту
bool is_array() // проверка на последовательный массив
bool is_object() // проверка на ассоциативный контейнер
bool is_long(), is_double(), is_string(), is_bool() // проверка на содержание скалярного типа данныхbool Contains(string key); // для ассоциативного контейнера
Context this[int index]; // для последовательного массива, элемент с указанием доступа и проверкой границ
Context this[string key]; // для ассоциативного контейнера, доступ или вставка данных
Context GetByKey(string key); // для ассоциативного контейнера, с проверкой границ
Context GetByIndex(int index); // для ассоциативного контейнера, с проверкой границ
ulong Length(); // возвращается число элементов контейнера
bool IsNone(); // проверка на пустоту
bool IsArray(); // проверка на последовательный массив
bool IsObject(); // проверка на ассоциативный контейнер
bool IsLong(), IsDouble(), IsString(), IsBool(); // проверка на содержание скалярного типа данныхvoid clear();
boolean contains(String key); // для ассоциативного контейнера
Context get(long index); // для последовательного массива, элемент с указанием доступа и проверкой границ
Context get(String key); // для ассоциативного контейнера, доступ или вставка данных
long size(); // возвращается число элементов контейнера
boolean isNone(); // проверка на пустоту
boolean isArray(); // проверка на последовательный массив
boolean isObject(); // проверка на ассоциативный контейнер
boolean isLong(), isDouble(), isString(), isBool(); // проверка на содержание скалярного типа данныхметоды FacerecService связанные с Context:
- C++
- Python
- Flutter
- C#
- Java
// получение Context из файла изображения
pbio::Context createContextFromEncodedImage(const uint8_t* data, uint64_t dataSize);
pbio::Context createContextFromEncodedImage(const std::vector<uint8_t>& data);
pbio::Context createContextFromEncodedImage(const std::string& data);
pbio::Context createContextFromEncodedImage(const std::vector<char>& data);
// получение Context из байтов изображения
pbio::Context createContextFromFrame(uint8_t* data, int32_t width, int32_t height, pbio::Context::Format format, int32_t baseAngle);# получение Context из файла изображения
def create_context_from_encoded_image(self, data: bytes) -> Context
# получение Context из байтов изображения
def create_context_from_frame(self, data: bytes, width: int, height: int, format: ContextFormat, base_angle: int) -> Context:// получение Context из файла изображения
Context createContextFromEncodedImage(Uint8List data);
// получение Context из байтов изображения
Context createContextFromFrame(Uint8List data, int width, int height, {ContextFormat format, int baseAngle});// получение Context из файла изображения
Context CreateContextFromImage(byte[] data);
// получение Context из байтов изображения
Context CreateContextFromFrame(byte[] data, int width, int height, Context.Format format, int baseAngle);// получение Context из файла изображения
Context createContextFromEncodedImage(byte[] data);
// получение Context из байтов изображения
Context createContextFromFrame(byte[] data, int width, int height, Context.Format format, int baseAngle);
Бинарный формат изображений
Большинство процессинг-блоков выполняют операции с Context-контейнерами, содержащими изображения в бинарном формате:
{
"image" : {
"format": "NDARRAY",
"blob": "data pointer",
"dtype": "uint8_t",
"shape": [height, width, channels]
}
}
Ключ "blob"
содержит умный указатель на данные. Указатель устанавливается функцией void Context::setDataPtr(void* ptr, int copy_sz)
,
где copy_sz
— размер памяти в байтах, который будет скопирован, и затем автоматически освобождается, когда заканчивается время жизни объекта Context.
Копирование не будет выполнено, если в качестве аргумента copy_sz
будет передан 0
. В этом случае объект Context не контролирует время жизни объекта, на который он указывает.
Вы также можете аллоцировать "сырую" память, например, чтобы скопировать данные позже, передавая nullptr и размер в качестве аргументов setDataPtr
.
Ключ "dtype"
может содержать одно из следующих значений: "uint8_t"
, "int8_t"
, "uint16_t"
, "int16_t"
, "int32_t"
, "float"
, "double"
.
Каждому значению соответствует определенный тип OpenCV: CV_8U
, CV_8S
, CV_16U
, CV_16S
, CV_32S
, CV_32F
, CV_64F
.
Создание Context-контейнера c RGB-изображением
- C++
- Python
- Flutter
- C#
- Java
- Прочитайте изображение из файла:
// read the image from file
std::string inputImagePath = "{path_to_image}";
std::ifstream imageFile(inputImagePath, std::ios::binary);
std::istreambuf_iterator<char> start(file);
std::vector<char> imageData(start, std::istreambuf_iterator<char>());
3 Создайте контейнер с изображением
pbio::Context ioData = service->createContextFromEncodedImage(imageData);
- Прочитайте изображение из файла:
# read the image from file
input_image_path = "{path_to_image}"
image_data = bytes()
with open(input_image_path, "rb") as image_file:
image_data = image_file.read()
- Создайте контейнер с изображением:
ioData = service.create_context_from_encoded_image(image_data)
- Прочитайте изображение из файла:
// read the image from file
File file = File("{imagePath}");
final Uint8List bytes = await file.readAsBytes();
- Создайте контейнер с изображением:
Context ioData = service.createContextFromEncodedImage(bytes);
- Прочитайте изображение из файла:
// read the image from file
string inputImagePath = "<path_to_image>"
byte[] imageData = File.ReadAllBytes(inputImagePath);
- Создайте контейнер с изображением:
Context ioData = service.CreateContextFromImage(imageData);
- Прочитайте изображение из файла:
// read the image from file
final String inputImagePath = "<path_to_image>";
byte[] imageData = Files.readAllBytes(Paths.get(inputImagePath));
- Создайте контейнер с изображением:
Context ioData = service.createContextFromEncodedImage(imageData);
Процессинг-блоки
Типы процессинг-блоков
- FACE_DETECTOR
- HUMAN_BODY_DETECTOR
- HUMAN_POSE_ESTIMATOR
- OBJECT_DETECTOR
- FACE_FITTER
- EMOTION_ESTIMATOR
- AGE_ESTIMATOR
- GENDER_ESTIMATOR
- MASK_ESTIMATOR
- LIVENESS_ESTIMATOR
- QUALITY_ASSESSMENT_ESTIMATOR
- FACE_TEMPLATE_EXTRACTOR
- TEMPLATE_INDEX
- MATCHER_MODULE
- VERIFICATION_MODULE
Примеры использования Processing Block API демонстрируются в:
- Сэмпле processing_block_demo на C++
- Примерах examples/python/processing_blocks/ на Python
- Сэмпле processing_block_demo на Flutter
Настраиваемые параметры процессинг-блоков
unit_type: string
— главный параметр процессинг-блока, определяет тип создаваемого модуля.modification: string
— опциональный параметр, определяет модификацию процессинг-блока. Если не указан, то будет использоваться значение по умолчанию.version: int64
— опциональный параметр, определяет версию модификации процессинг-блока. Если не указан, то будет использоваться значение по умолчанию.model_path: string
— опциональный параметр, определяет путь до модели процессинг-блока. Если не указан, то будет использоваться значение по умолчанию.use_cuda: bool
— опциональный параметр, отвечает за запук процессинг-блока на GPU. Значение по умолчанию —false
.use_legacy: bool
— опциональный параметр, нужен для использования более старой билиотеки onnxruntime. Значение по умолчанию —false
.ONNXRuntime
— ключ для параметров конфигурации onnxruntime:library_path: string
— путь до библиотек onnxruntime, по умолчанию путь до директории с libfacerec.so.intra_op_num_threads: int64
– число потоков для распараллеливания модуля, по умолчанию равно 1.
Создание процессинг-блока
Создайте Context-контейнер, укажите нужные вам параметры и передайте его в метод
FacerecService.createProcessingBlock()
.- C++
- Python
- Flutter
- C#
- Java
// обязательно, укажите имя процессинг-блока
auto configCtx = service->createContext();
configCtx["unit_type"] = "{name_of_processing_block}";
// если не указать, то будет использоваться значение по умолчанию
configCtx["modification"] = "{modification}";
// если не указать, то будет использоваться первая версия модификации
configCtx["version"] = {version};
// модели по умолчанию расположены в директории дистрибутива Face SDK: share/processing_block/{modification}/({version}/ или {version}.enc)
// вы можете задать ваш собственный путь до модели
configCtx["model_path"] = "{path_to_model_file}";
// библиотека onnxruntime по умолчанию расположена в директории дистрибутива Face SDK: "lib" для платформы Linux или "bin" для платформы Windows
// вы можете задать ваш собственный путь до библиотеки onnxruntime
// если путь до библиотеки не указан, то будет использоваться стандартный порядок поиска, используемый в данной ОС
configCtx["ONNXRuntime"]["library_path"] = "../lib"; // для Linux
configCtx["ONNXRuntime"]["library_path"] = "../bin"; // для Windows
// опционально, значение "true" для ускорения процессинг-блоков на GPU (только для блоков с поддержкой CUDA)
configCtx["use_cuda"] = false;
pbio::ProcessingBlock processing_block = service->createProcessingBlock(configCtx);configDict = {};
# обязательно, укажите имя процессинг-блока
configDict["unit_type"] = "{name_of_processing_block}"
# если не указать, то будет использоваться значение по умолчанию
configDict["modification"] = "{modification}"
# если не указать, то будет использоваться первая версия модификации
configDict["version"] = {version}
# модели по умолчанию расположены в директории дистрибутива Face SDK: share/processing_block/{modification}/({version}/ или {version}.enc)
# вы можете задать ваш собственный путь до модели
configDict["model_path"] = "{path_to_model_file}"
# библиотека onnxruntime по умолчанию расположена в директории дистрибутива Face SDK: "lib" для платформы Linux или "bin" для платформы Windows
# вы можете задать ваш собственный путь до библиотеки onnxruntime
# если путь до библиотеки не указан, то будет использоваться стандартный порядок поиска, используемый в данной ОС
configDict["ONNXRuntime"]["library_path"] = "../lib" # для Linux
configDict["ONNXRuntime"]["library_path"] = "../bin" # для Windows
# опционально, значение "true" для ускорения процессинг-блоков на GPU (только для блоков с поддержкой CUDA)
configDict["use_cuda"] = False
processing_block = service.create_processing_block(configDict);Map<String, dynamic> configMap = {};
// обязательно, укажите имя процессинг-блока
configMap["unit_type"] = "{name_of_processing_block}";
// если не указать, то будет использоваться значение по умолчанию
configMap["modification"] = "{modification}";
// если не указать, то будет использоваться первая версия модификации
configMap["version"] = {version};
// модели по умолчанию расположены в директории дистрибутива Face SDK: share/processing_block/{modification}/({version}/ или {version}.enc)
// вы можете задать ваш собственный путь до модели
configMap["model_path"] = "{path_to_model_file}";
processing_block = service.createProcessingBlock(configMap);Dictionary<object, object> configDict = new Dictionary<object, object>();
// обязательно, укажите имя процессинг-блока
configDict["unit_type"] = "<name_of_processing_block>";
// если не указать, то будет использоваться значение по умолчанию
configDict["modification"] = "<modification>";
// если не указать, то будет использоваться первая версия модификации
configDict["version"] = <version>;
// модели по умолчанию расположены в директории дистрибутива Face SDK: share/processing_block/<modification>/(<version>/ или <version>.enc)
// вы можете задать ваш собственный путь до модели
configDict["model_path"] = "<path_to_model_file>";
// библиотека onnxruntime по умолчанию расположена в директории дистрибутива Face SDK: "lib" для платформы Linux или "bin" для платформы Windows
// вы можете задать ваш собственный путь до библиотеки onnxruntime
// если путь до библиотеки не указан, то будет использоваться стандартный порядок поиска, используемый в данной ОС
configDict["ONNXRuntime"]["library_path"] = "../lib"; # для Linux
configDict["ONNXRuntime"]["library_path"] = "../bin"; # для Windows
// опционально, значение "true" для ускорения процессинг-блоков на GPU (только для блоков с поддержкой CUDA)
configDict["use_cuda"] = False;
ProcessingBlock processingBlock = service.CreateProcessingBlock(configDict);// обязательно, укажите имя процессинг-блока
Context configCtx = service.createContext();
configCtx.get("unit_type").setString("{name_of_processing_block}");
// если не указать, то будет использоваться значение по умолчанию
configCtx.get("modification").setString("{modification}");
// если не указать, то будет использоваться первая версия модификации
configCtx.get("version").setLong({version});
// модели по умолчанию расположены в директории дистрибутива Face SDK: share/processing_block/{modification}/({version}/ или {version}.enc)
// вы можете задать ваш собственный путь до модели
configCtx.get("model_path").setString("{path_to_model_file}");
// библиотека onnxruntime по умолчанию расположена в директории дистрибутива Face SDK: "lib" для платформы Linux или "bin" для платформы Windows
// вы можете задать ваш собственный путь до библиотеки onnxruntime
// если путь до библиотеки не указан, то будет использоваться стандартный порядок поиска, используемый в данной ОС
configCtx.get("ONNXRuntime").get("library_path").setString("../lib"); // для Linux
configCtx.get("ONNXRuntime").get("library_path").setString("../bin"); // для Windows
// опционально, значение "true" для ускорения процессинг-блоков на GPU (только для блоков с поддержкой CUDA)
configCtx["use_cuda"] = false;
configCtx.get("use_cuda").setBool(false);
ProcessingBlock processing_block = service.createProcessingBlock(configCtx);Подготовьте входной Context-контейнер с изображением и передайте в процессинг-блок.
- C++
- Python
- Flutter
- C#
- Java
std::string inputImagePath = "{path_to_image}";
std::ifstream imageFile(inputImagePath, std::ios::binary);
std::istreambuf_iterator<char> start(file);
std::vector<char> imageData(start, std::istreambuf_iterator<char>());
// формирование входного контейнера Context
pbio::Context ioData = service->createContextFromEncodedImage(imageData);
// Вызов процессинг-блока
processing_block(ioData);input_image_path = "{path_to_image}"
image_data = bytes()
with open(input_image_path, "rb") as image_file:
image_data = image_file.read()
# Формирование входного контейнера Context
ioData = service.create_context_from_encoded_image(image_data)
# Вызов процессинг-блока
processing_block(ioData);File file = File("{imagePath}");
final Uint8List bytes = await file.readAsBytes();
Context imgCtx =
// Формирование входного контейнера Context
Context ioData = service.createContextFromEncodedImage(bytes);
// Вызов процессинг-блока
processing_block.process(ioData);string inputImagePath = "<path_to_image>"
byte[] imageData = File.ReadAllBytes(inputImagePath);
// формирование контейнера Context с бинарным изображением
Context ioData = service.CreateContextFromImage(imageData);
// Вызов процессинг-блока
processingBlock.Invoke(ioData);final String inputImagePath = "<path_to_image>";
byte[] imageData = Files.readAllBytes(Paths.get(inputImagePath));
// формирование входного контейнера Context
Context ioData = service.createContextFromEncodedImage(imageData);
// Вызов процессинг-блока
processing_block.process(ioData);
Ускорение на GPU
Процессинг-блоки могут быть использованы с ускорением на GPU. Для этого необходимо определить ключ "use_cuda"
со значением true
для Context-контейнера процессинг-блока.
Для запуска процессинг-блоков на CUDA версии 10.1 необходимо дополнительно определить ключ "use_legacy"
со значением true
для Context-контейнера процессинг-блока.
(См. Настраиваемые параметры процессинг-блоков).
Поддерживаемые версии CUDA см. на странице Системные требования для использования GPU