Детекция тел
Human Body Detector
Компонент Human Body Detector используется для обнаружения человеческих тел на изображении.
Результат детекции - координаты прямоугольника, ограничивающего обнаруженное тело человека.
На этой странице вы узнаете как запустить демонстрационный сэмпл body_detector для детекции человеческих тел на изображении и как интегрировать компонент Human Body Detector в проект на C++.
Human Body Detection Sample
Сэмпл body_detector демонстрирует детекцию человеческих тел на изображении.
Для запуска сэмпла body_detector необходим дистрибутив Face SDK версии 3.14 (или выше) с установленными компонентами для платформ Windows или Linux (в соответствии с используемой вами ОС).
Если Face SDK не установлен, следуйте инструкциям Начало работы. Выберите нужную платформу на этапе "Выбор компонентов".
Если Face SDK установлен без компонентов платформ Windows или Linux, используйте утилиту maintenancetool и установите нужную платформу выбрав ее на этапе "Выбор компонентов".
Для запуска сэмпла body_detector используются следующие аргументы:
- Путь до изображения
- Путь до файла body.enc
Путь по умолчанию до файла модели Human Body Detector: share/bodydetectors/body.enc в корневой директории Face SDK.
Примеры консольных команд для запуска сэмпла body_detector из директории bin:
- Linux:
./body_detector group/01.jpg ../share/bodydetectors/body.enc
- Windows:
.\body_detector.exe group\01.jpg ..\share\bodydetectors\body.enc
Результат детекции человеческих тел на изображении отобразиться в новом окне.
Результат детекции человеческих тел
В случае возникновения неполадок, соответствующие сообщения будут выведены в консоль.
Устранение неполадок
Ошибка
Assertion failed (ERROR: not found libonnxruntime.so), error code: 0x032ad038
:- Проверьте наличие файла библиотеки lib/libonnxruntime.so в корневой директории Face SDK
- Добавть путь к библиотеке lib/libonnxruntime.so в переменную окружения
LD_LIBRARY_PATH
Ошибка
Assertion failed (ERROR: not found onnxruntime.dll), error code: 0x032ad038
:- Проверьте наличие файла библиотеки bin/onnxruntime.dll в корневой директории Face SDK
Исходный код сэмпла body_detector доступен по ссылке. Так же исходный код и инструкция по сборке (файл README.txt) доступны в директории examples/cpp/body_detector/ дистрибутива Face SDK.
Детекция тел (C++)
В этом разделе вы узнаете как интегрировать компонент Human Body Detector в проект на С++.
Context
Context - это гетерогенный контейнер, состоящий из набора иерархически организованных данных, представленных как пары ключ-значение.
Ближайший аналог Context - объект JSON. Каждый объект Context может содержать: скалярный объект (integer, real, boolean, string),
указатель на область памяти, массив объектов Context, ассоциативный контейнер пар <string, Context>
с неограниченной вложенностью.
Пример использования объекта Context
Context array_elem0;
array_elem0["name"] = "Julius Zeleny";
array_elem0["phone"] = 11111111111l;
array_elem0["social_score"] = 0.999;
array_elem0["verified"] = true;
std::cout << array_elem0["name"].getString() << std::endl; // "Julius Zeleny"
std::cout << array_elem0["phone"].getLong() << std::endl; // 11111111111l
std::cout << array_elem0["social_score"].getDouble() << std::endl;// 0.999
std::cout << array_elem0["verified"].getBool() << std::endl; // 1
Context array_elem1;
array_elem1["name"] = "Owen Cohron";
array_elem1["phone"] = 22222222222;
array_elem1["social_score"] = 0.999;
array_elem1["verified"] = false;
Context array_elem2;
array_elem2["name"] = std::string("Sarah Connor");
array_elem2["phone"] = 333333333l;
array_elem2["social_score"] = 0.5;
array_elem2["verified"] = true;
std::cout << array_elem2["name"].getString() << std::endl; // "Sarah Connor"
Context array;
array.push_back(array_elem0);
array.push_back(array_elem1);
array.push_back(array_elem2);
std::cout << array[0]["phone"].getLong() << std::endl; // 11111111111l
std::cout << array[1]["phone"].getLong() << std::endl; // 22222222222
std::cout << array[2]["phone"].getLong() << std::endl; // 333333333l
size_t array_sz = array.size();
std::cout << array_sz << std::endl; // 3
for(size_t i = 0; i < array_sz; ++i) {
array[i]["phone"];
}
Context full;
full["friends"] = array;
std::cout << full["friends"][1]["social_score"].getDouble() << std::endl; // 0.999
// copy cv::Mat to Context
int width{640}, height{480}, channels{3};
cv::Mat img = cv::imread("photo.jpg");
full["img"]["dtype"] = "uint8";
full["img"]["shape"].push_back(width);
full["img"]["shape"].push_back(height);
full["img"]["shape"].push_back(channels);
full["img"]["ptr"] = img.data;
full["img"]["data"].setDataPtr(img.data, img.total()*img.elemSize());
// create cv::Mat from Context
unsigned char* img_buf = full["img"]["data"].getDataPtr();
cv::Mat imgCopy = cv::Mat(height, width, CV_8UC3, img_buf);
1. Создание Human Body Detector
1.1. Создайте FacerecService.
1.2. Создайте контейнер Context:
auto modelCtx = service->createContext();
1.3. Для создания блока обработчика (Processing block), в созданном контейнере Context определите следующие поля:
// обязательно
modelCtx["unit_type"] = "HUMAN_BODY_DETECTOR";
// обязательно
// путь по умолчанию до файла модели Human Body Detector: _share/bodydetectors/body.enc_ в корневой директории Face SDK.
modelCtx["model_path"] = "../share/bodydetectors/body.enc";
// значение по умолчанию 0.5
modelCtx["confidence_threshold"] = 0.2;
// значение по умолчанию 0.5
modelCtx["iou_threshold"] = 0.4;
// библиотека onnxruntime по умолчанию расположена в директории дистрибутива Face SDK: "lib" для платформы Linux или "bin" для платформы Windows
// вы можете задать ваш собственный путь до библиотеки onnxruntime
// если путь до библиотеки не указан, то будет использоваться стандартный порядок поиска, используемый в данной ОС
modelCtx["ONNXRuntime"]["library_path"] = "../lib"
1.4. Используя контейнер Context, создайте Human Body Detector Processing block:
pbio::ProcessingBlock bodyDetector = service->createProcessingBlock(modelCtx);
2. Детекция тел
Детектор тел принимает контейнер Context, содержащий изображение в бинарном формате:
/*
{
"image" : { "format": "NDARRAY",
"blob": <blob_value>,
"dtype": "uint8_t",
"shape": [] }
}
*/
Ключ "blob"
содержит указатель на данные. Указатель устанавливается функцией void Context::setDataPtr(void* ptr, int copy_sz)
,
где copy_sz
- это размер памяти в байтах, которая будет скопирована и далее автоматически освобождена. Копирование не выполняется если в качестве аргумента copy_sz
передан 0.
Ключ "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
.
2.1. Создайте контейнер Context для изображения, используя метод createContext()
:
auto imgCtx = service->createContext();
2.2. Загрузите RGB-изображение как объект cv::Mat
:
cv::Mat image = cv::imread(input_image_path, cv::IMREAD_COLOR);
cv::Mat input_image;
cv::cvtColor(image, input_image, cv::COLOR_BGR2RGB);
2.3. Конвертируйте изображение из cv::Mat
в бинарный формат и добавьте его в контейнер Context:
void cvMatToBSM(pbio::Context& bsmCtx, const cv::Mat img, bool copy)
{
bsmCtx["format"] = "NDARRAY";
size_t copy_sz = copy ? img.total()*img.elemSize() : 0;
bsmCtx["blob"].setDataPtr(img.data, copy_sz);
bsmCtx["dtype"] = CvTypeToStr.at(img.depth());
for(int i = 0; i < img.dims; ++i)
bsmCtx["shape"].push_back(img.size[i]);
bsmCtx["shape"].push_back(img.channels());
}
cvMatToBSM(imgCtx, input_image);
2.4. Создайте контейнер Context:
auto ioData = service->createContext();
ioData["image"] = imgCtx;
2.5. Вызовите метод bodyDetector()
и передайте контейнер ioData
:
bodyDetector(ioData);
Метод bodyDetector()
добавит результат обработки сэмплов (изображений) в контейнер ioData
.
Формат выходных данных представляет собой список объектов, доступный по ключу "objects"
.
Каждый объект списка имеет:
- Ключ
"class"
со значением "body" - Ключ
"bbox"
(bounding box) содержит массив из четырех чисел типа long{x1, y1, x2, y2}
- координаты в пикселях на исходном изображении - Ключ "
score"
содержит число типа float в диапазоне [0,1]
/*
{
"objects": [{ "id": <id_value>,
"class": "body",
"score": <score_value>,
"bbox": [] }]
}
*/
Объекты Context позволяют итерироваться по своим значениям, поэтому вы можете использовать следующий код для получения результата детекции тел и отрисовки результата на исходном изображении:
for(const auto& obj : ioData["objects"])
{
if(obj["class"].getString().compare("body"))
continue;
const auto& rectCtx = obj.at("bbox");
cv::Rect rect(cv::Point{rectCtx[0].getLong(), rectCtx[1].getLong()},
cv::Point{rectCtx[2].getLong(), rectCtx[3].getLong()});
cv::rectangle(img, rect, {0, 255, 0}, 1);
}
cv::imshow("img", img);
cv::waitKey();
3. Ускорение на GPU
Human Body Detector может быть использован с ускорением на GPU (CUDA). Для этого необходимо определить ключ "use_cuda"
со значением true
для Context-контейнера блока обработчика (см. Создание Human Body Detector).
- Системные требования:
- Nvidia GPU Driver >= 410.48
- CUDA Toolkit 10.1
- cuDNN 7
- (Для Windows) Microsoft Visual C++ Redistributable for Visual Studio 2019
- Требования к оборудованию:
- графический процессор (GPU) с поддержкой CUDA (NVIDIA GTX 1050 Ti и выше)