659 lines
30 KiB
C++
659 lines
30 KiB
C++
#include "nv_infer_server_manager.hpp"
|
||
|
||
// #define NVDS_USER_OBJECT_META_LANDMARKS_AND_SOURCE_ID
|
||
// (nvds_get_user_meta_type("NVIDIA.NVINFER.USER_META"))
|
||
#define NVDS_USER_OBJECT_META_LANDMARKS_AND_SOURCE_ID \
|
||
(nvds_get_user_meta_type(const_cast<gchar *>("NVIDIA.NVINFER.USER_META")))
|
||
|
||
#define MAX_DISPLAY_LEN 64
|
||
#define PGIE_CLASS_ID_PERSON 0
|
||
#define IMPRECISE_FACE_CLASS_ID 1
|
||
#define PGIE_DETECTED_CLASS_NUM 1
|
||
#define BODY_COMPONENT_ID 1
|
||
#define IMPRECISE_FACE_COMPONENT_ID 2
|
||
#define BODY_TENSOR_SIZE 57
|
||
#define MAX_BODY_PER_FRAME 100
|
||
|
||
gint NvInferServerManager::frame_number = 0;
|
||
unsigned int NvInferServerManager::PGIE_NET_WIDTH = 1;
|
||
unsigned int NvInferServerManager::PGIE_NET_HEIGHT = 1;
|
||
unsigned int NvInferServerManager::MUXER_OUTPUT_WIDTH = 1;
|
||
unsigned int NvInferServerManager::MUXER_OUTPUT_HEIGHT = 1;
|
||
guint NvInferServerManager::use_device_mem = 0;
|
||
float NvInferServerManager::threshold_body_detection = 0;
|
||
unsigned int NvInferServerManager::nvds_lib_major_version = NVDS_VERSION_MAJOR;
|
||
unsigned int NvInferServerManager::nvds_lib_minor_version = NVDS_VERSION_MINOR;
|
||
|
||
const gchar pgie_class_str[PGIE_DETECTED_CLASS_NUM][32] = {"Person_NVINFER"};
|
||
const gchar imprecise_face_str[PGIE_DETECTED_CLASS_NUM][32] = {
|
||
"ImpreciseFace_NVINFER"};
|
||
|
||
/* nvds_lib_major_version and nvds_lib_minor_version is the version number of
|
||
* deepstream sdk */
|
||
|
||
unsigned int nvds_lib_major_version = NVDS_VERSION_MAJOR;
|
||
unsigned int nvds_lib_minor_version = NVDS_VERSION_MINOR;
|
||
|
||
NvInferServerManager::NvInferServerManager() {
|
||
const auto &config = ConfigManager::get_instance().get_config();
|
||
pgie_batch_size = config["pgie_batch_size"];
|
||
inferserver_pgie_config_file =
|
||
config["inferserver_pgie_config_file"].get<std::string>();
|
||
PGIE_NET_WIDTH = config["PGIE_NET_WIDTH"];
|
||
PGIE_NET_HEIGHT = config["PGIE_NET_HEIGHT"];
|
||
MUXER_OUTPUT_WIDTH = config["MUXER_OUTPUT_WIDTH"];
|
||
MUXER_OUTPUT_HEIGHT = config["MUXER_OUTPUT_HEIGHT"];
|
||
threshold_body_detection = config["threshold_body_detection"];
|
||
}
|
||
|
||
bool NvInferServerManager::create_nv_infer_server(int num_sources) {
|
||
/* Configure the nvinferserver element using the config file. */
|
||
primary_detector =
|
||
gst_element_factory_make("nvinferserver", "primary-nvinference-engine");
|
||
g_object_set(G_OBJECT(primary_detector), "config-file-path",
|
||
inferserver_pgie_config_file.c_str(), "unique-id", 1, NULL);
|
||
|
||
/* Override the batch-size set in the config file with the number of
|
||
* sources. */
|
||
g_object_get(G_OBJECT(primary_detector), "batch-size", &pgie_batch_size,
|
||
NULL);
|
||
if (pgie_batch_size != num_sources) {
|
||
g_printerr(
|
||
"WARNING: Overriding infer-config batch-size (%d) with number of "
|
||
"sources (%d)\n",
|
||
pgie_batch_size, num_sources);
|
||
g_object_set(G_OBJECT(primary_detector), "batch-size", num_sources,
|
||
NULL);
|
||
}
|
||
if (!primary_detector) {
|
||
g_printerr("Could not create primary detector. Exiting.\n");
|
||
return false;
|
||
}
|
||
return true;
|
||
}
|
||
|
||
// Probe function to inspect NvDsObjectMeta
|
||
|
||
// GstPadProbeReturn NvInferServerManager::osd_sink_pad_buffer_probe(
|
||
// GstPad *pad, GstPadProbeInfo *info, gpointer user_data) {
|
||
// (void)pad;
|
||
// (void)user_data;
|
||
// GstBuffer *buf = (GstBuffer *)info->data;
|
||
|
||
// // Retrieve batch metadata from buffer
|
||
// NvDsBatchMeta *batch_meta = gst_buffer_get_nvds_batch_meta(buf);
|
||
// if (!batch_meta) {
|
||
// std::cerr << "No batch metadata found\n";
|
||
// return GST_PAD_PROBE_OK;
|
||
// }
|
||
|
||
// // probe sees the frame metadata (NvDsFrameMeta) —
|
||
// // but no object metadata (NvDsObjectMeta) was attached to that frame.
|
||
|
||
// for (NvDsMetaList *l_frame = batch_meta->frame_meta_list; l_frame !=
|
||
// NULL;
|
||
// l_frame = l_frame->next) {
|
||
// NvDsFrameMeta *frame_meta = (NvDsFrameMeta *)(l_frame->data);
|
||
// // std::cout << "Frame number: " << frame_meta->frame_num <<
|
||
// std::endl;
|
||
// // if (frame_meta->obj_meta_list == NULL) {
|
||
// // std::cout << " ⚠️ No object metadata for this frame.\n";
|
||
// // }
|
||
|
||
// for (NvDsMetaList *l_obj = frame_meta->obj_meta_list; l_obj != NULL;
|
||
// l_obj = l_obj->next) {
|
||
// NvDsObjectMeta *obj_meta = (NvDsObjectMeta *)(l_obj->data);
|
||
|
||
// std::cout << " Object ID: " << obj_meta->object_id << std::endl;
|
||
// std::cout << " Class ID: " << obj_meta->class_id << std::endl;
|
||
// std::cout << " Label: "
|
||
// << (obj_meta->obj_label ? obj_meta->obj_label : "N/A")
|
||
// << std::endl;
|
||
// std::cout << " BBox: x=" << obj_meta->rect_params.left
|
||
// << " y=" << obj_meta->rect_params.top
|
||
// << " w=" << obj_meta->rect_params.width
|
||
// << " h=" << obj_meta->rect_params.height << std::endl;
|
||
// }
|
||
// }
|
||
// return GST_PAD_PROBE_OK;
|
||
// }
|
||
|
||
// // Attach probe to a pad in the pipeline
|
||
// void NvInferServerManager::attach_probe_to_element(GstElement *nvosd) {
|
||
// GstPad *sink_pad = gst_element_get_static_pad(nvosd, "src");
|
||
// if (!sink_pad) {
|
||
// std::cerr << "Unable to get nvosd sink pad\n";
|
||
// return;
|
||
// }
|
||
|
||
// gst_pad_add_probe(sink_pad, GST_PAD_PROBE_TYPE_BUFFER,
|
||
// osd_sink_pad_buffer_probe_new, NULL, NULL);
|
||
// gst_object_unref(sink_pad);
|
||
// }
|
||
|
||
// /* This is the buffer probe function that we have registered on the sink pad
|
||
// * of the OSD element. All the infer elements in the pipeline shall attach
|
||
// * their metadata to the GstBuffer, here we will iterate & process the
|
||
// metadata
|
||
// * forex: class ids to strings, counting of class_id objects etc. */
|
||
// GstPadProbeReturn NvInferServerManager::osd_sink_pad_buffer_probe_new(
|
||
// GstPad *pad, GstPadProbeInfo *info, gpointer u_data) {
|
||
// (void)pad;
|
||
// (void)u_data;
|
||
// GstBuffer *buf = (GstBuffer *)info->data;
|
||
// guint num_rects = 0;
|
||
// guint person_count = 0;
|
||
// NvDsObjectMeta *obj_meta = NULL;
|
||
// NvDsMetaList *l_frame = NULL;
|
||
// NvDsMetaList *l_obj = NULL;
|
||
// NvDsDisplayMeta *display_meta = NULL;
|
||
|
||
// NvDsBatchMeta *batch_meta = gst_buffer_get_nvds_batch_meta(buf);
|
||
|
||
// for (l_frame = batch_meta->frame_meta_list; l_frame != NULL;
|
||
// l_frame = l_frame->next) {
|
||
// NvDsFrameMeta *frame_meta = (NvDsFrameMeta *)(l_frame->data);
|
||
// int offset = 0;
|
||
// for (l_obj = frame_meta->obj_meta_list; l_obj != NULL;
|
||
// l_obj = l_obj->next) {
|
||
// obj_meta = (NvDsObjectMeta *)(l_obj->data);
|
||
// if (obj_meta->class_id == PGIE_CLASS_ID_PERSON) {
|
||
// person_count++;
|
||
// num_rects++;
|
||
// std::cout << "In OSD sink "
|
||
// << "x = " << obj_meta->rect_params.left
|
||
// << " y = " << obj_meta->rect_params.top
|
||
// << " w = " << obj_meta->rect_params.width
|
||
// << " h = " << obj_meta->rect_params.height
|
||
// << " score = " << obj_meta->confidence
|
||
// << " Object ID: " << obj_meta->object_id
|
||
// << std::endl;
|
||
// }
|
||
// }
|
||
// display_meta = nvds_acquire_display_meta_from_pool(batch_meta);
|
||
// NvOSD_TextParams *txt_params = &display_meta->text_params[0];
|
||
// display_meta->num_labels = 1;
|
||
// txt_params->display_text = (gchar *)g_malloc0(MAX_DISPLAY_LEN);
|
||
// offset = snprintf(txt_params->display_text, MAX_DISPLAY_LEN,
|
||
// "Person = %d ", person_count);
|
||
// (void)offset;
|
||
|
||
// /* Now set the offsets where the string should appear */
|
||
// txt_params->x_offset = 10;
|
||
// txt_params->y_offset = 12;
|
||
|
||
// /* Font , font-color and font-size */
|
||
// txt_params->font_params.font_name = (gchar *)"Serif";
|
||
// txt_params->font_params.font_size = 10;
|
||
// txt_params->font_params.font_color.red = 1.0;
|
||
// txt_params->font_params.font_color.green = 1.0;
|
||
// txt_params->font_params.font_color.blue = 1.0;
|
||
// txt_params->font_params.font_color.alpha = 1.0;
|
||
|
||
// /* Text background color */
|
||
// txt_params->set_bg_clr = 1;
|
||
// txt_params->text_bg_clr.red = 0.0;
|
||
// txt_params->text_bg_clr.green = 0.0;
|
||
// txt_params->text_bg_clr.blue = 0.0;
|
||
// txt_params->text_bg_clr.alpha = 1.0;
|
||
|
||
// nvds_add_display_meta_to_frame(frame_meta, display_meta);
|
||
// }
|
||
// g_print(
|
||
// "In OSD sink "
|
||
// "Frame Number = %d "
|
||
// "Person Count = %d\n",
|
||
// frame_number, person_count);
|
||
|
||
// frame_number++;
|
||
// return GST_PAD_PROBE_OK;
|
||
// }
|
||
|
||
/* This is the buffer probe function that we have registered on the src pad
|
||
* of the PGIE's next queue element. PGIE element in the pipeline shall attach
|
||
* its NvDsInferTensorMeta to each frame metadata on GstBuffer, here we will
|
||
* iterate & parse the tensor data to get detection bounding boxes. The result
|
||
* would be attached as object-meta(NvDsObjectMeta) into the same frame
|
||
* metadata.
|
||
*/
|
||
GstPadProbeReturn NvInferServerManager::pgie_pad_buffer_probe(
|
||
GstPad *pad, GstPadProbeInfo *info, gpointer u_data) {
|
||
(void)pad;
|
||
gboolean *use_new_mux = (gboolean *)u_data;
|
||
guint stream_width = 0, stream_height = 0;
|
||
|
||
static NvDsInferNetworkInfo networkInfo{PGIE_NET_WIDTH, PGIE_NET_HEIGHT, 3};
|
||
NvDsBatchMeta *batch_meta =
|
||
gst_buffer_get_nvds_batch_meta(GST_BUFFER(info->data));
|
||
|
||
/* Iterate each frame metadata in batch */
|
||
for (NvDsMetaList *l_frame = batch_meta->frame_meta_list; l_frame != NULL;
|
||
l_frame = l_frame->next) {
|
||
NvDsFrameMeta *frame_meta = (NvDsFrameMeta *)l_frame->data;
|
||
|
||
// to solve track not showing up issue
|
||
nvds_acquire_meta_lock(batch_meta);
|
||
frame_meta->bInferDone = TRUE;
|
||
nvds_release_meta_lock(batch_meta);
|
||
if (*use_new_mux) {
|
||
stream_width = frame_meta->source_frame_width;
|
||
stream_height = frame_meta->source_frame_height;
|
||
// These values come from the actual source (decoder) frame size
|
||
// before batching/muxing. They tell us the native resolution of the
|
||
// incoming camera/RTSP/file. If have multiple sources with
|
||
// different resolutions, these values can differ per source/frame.
|
||
// Use this if need the original stream resolution (e.g., for
|
||
// scaling bounding boxes back to source coordinates).
|
||
} else {
|
||
stream_width = MUXER_OUTPUT_WIDTH;
|
||
stream_height = MUXER_OUTPUT_HEIGHT;
|
||
// These are the dimensions configured in nvstreammux (width /
|
||
// height). All sources fed into the muxer get scaled/padded to this
|
||
// resolution before being passed to downstream elements (like
|
||
// PGIE). So PGIE always “sees” frames at muxer resolution, not the
|
||
// raw input resolution. Use this if need the effective frame size
|
||
// that PGIE is processing (i.e., what TensorRT sees).
|
||
}
|
||
// Inside PGIE (nvinfer), the correct dimensions are the muxer output
|
||
// width/height, because frames are resized by nvstreammux before
|
||
// inference. If want the original camera’s resolution, use
|
||
// frame_meta->source_frame_width / source_frame_height.
|
||
// nvmultiurisrcbin internally creates a nvstreammux before sending
|
||
// buffers downstream. That means by the time PGIE sees frames, they are
|
||
// already scaled to the muxer’s output size.
|
||
|
||
// At PGIE input, the frame resolution is the muxer’s configured output
|
||
// size. Therefore the correct dimensions for PGIE are: stream_width =
|
||
// MUXER_OUTPUT_WIDTH; stream_height = MUXER_OUTPUT_HEIGHT; Why not
|
||
// frame_meta->source_frame_width? Those fields still exist in
|
||
// frame_meta, but they represent the original source stream resolution
|
||
// (camera/file). Since PGIE never directly sees that resolution (it
|
||
// only sees muxed frames), using these values inside PGIE would be
|
||
// misleading.
|
||
|
||
// For this pipeline, use MUXER_OUTPUT_WIDTH and MUXER_OUTPUT_HEIGHT to
|
||
// represent what PGIE actually processes. If later need to map
|
||
// detections back to the original stream resolution (e.g., for saving
|
||
// cropped images or re-streaming), then use
|
||
// frame_meta->source_frame_width and source_frame_height for scaling.
|
||
|
||
(void)stream_height;
|
||
(void)stream_width;
|
||
uint detected_persons = 0;
|
||
|
||
/* Iterate user metadata in frames to search PGIE's tensor metadata */
|
||
for (NvDsMetaList *l_user = frame_meta->frame_user_meta_list;
|
||
l_user != NULL; l_user = l_user->next) {
|
||
NvDsUserMeta *user_meta = (NvDsUserMeta *)l_user->data;
|
||
if (user_meta->base_meta.meta_type != NVDSINFER_TENSOR_OUTPUT_META)
|
||
continue;
|
||
detected_persons = extract_tensor_metadata(user_meta, networkInfo,
|
||
batch_meta, frame_meta);
|
||
}
|
||
|
||
NvDsDisplayMeta *display_meta = NULL;
|
||
display_meta = nvds_acquire_display_meta_from_pool(batch_meta);
|
||
NvOSD_TextParams *txt_params = &display_meta->text_params[0];
|
||
display_meta->num_labels = 1;
|
||
txt_params->display_text = (gchar *)g_malloc0(MAX_DISPLAY_LEN);
|
||
int offset = 0;
|
||
offset = snprintf(txt_params->display_text, MAX_DISPLAY_LEN,
|
||
"Person_NVInfer = %d ", detected_persons);
|
||
(void)offset;
|
||
|
||
/* Now set the offsets where the string should appear */
|
||
txt_params->x_offset = 10;
|
||
txt_params->y_offset = 12;
|
||
|
||
/* Font , font-color and font-size */
|
||
txt_params->font_params.font_name = (gchar *)"Serif";
|
||
txt_params->font_params.font_size = 10;
|
||
txt_params->font_params.font_color.red = 1.0;
|
||
txt_params->font_params.font_color.green = 1.0;
|
||
txt_params->font_params.font_color.blue = 1.0;
|
||
txt_params->font_params.font_color.alpha = 1.0;
|
||
|
||
/* Text background color */
|
||
txt_params->set_bg_clr = 1;
|
||
txt_params->text_bg_clr.red = 0.0;
|
||
txt_params->text_bg_clr.green = 0.0;
|
||
txt_params->text_bg_clr.blue = 0.0;
|
||
txt_params->text_bg_clr.alpha = 1.0;
|
||
|
||
nvds_add_display_meta_to_frame(frame_meta, display_meta);
|
||
}
|
||
// use_device_mem = 1 - use_device_mem;
|
||
return GST_PAD_PROBE_OK;
|
||
}
|
||
|
||
uint NvInferServerManager::extract_tensor_metadata(
|
||
NvDsUserMeta *user_meta, NvDsInferNetworkInfo networkInfo,
|
||
NvDsBatchMeta *batch_meta, NvDsFrameMeta *frame_meta) {
|
||
/* convert to tensor metadata */
|
||
NvDsInferTensorMeta *meta =
|
||
(NvDsInferTensorMeta *)user_meta->user_meta_data;
|
||
for (unsigned int i = 0; i < meta->num_output_layers; i++) {
|
||
NvDsInferLayerInfo *info = &meta->output_layers_info[i];
|
||
info->buffer = meta->out_buf_ptrs_host[i];
|
||
if (use_device_mem && meta->out_buf_ptrs_dev[i]) {
|
||
cudaMemcpy(meta->out_buf_ptrs_host[i], meta->out_buf_ptrs_dev[i],
|
||
info->inferDims.numElements * 4, cudaMemcpyDeviceToHost);
|
||
}
|
||
}
|
||
/* Parse output tensor and fill detection results into objectList.
|
||
*/
|
||
std::vector<NvDsInferLayerInfo> outputLayersInfo(
|
||
meta->output_layers_info,
|
||
meta->output_layers_info + meta->num_output_layers);
|
||
#if NVDS_VERSION_MAJOR >= 5
|
||
if (nvds_lib_major_version >= 5) {
|
||
if (meta->network_info.width != networkInfo.width ||
|
||
meta->network_info.height != networkInfo.height ||
|
||
meta->network_info.channels != networkInfo.channels) {
|
||
g_error("failed to check pgie network info\n");
|
||
}
|
||
}
|
||
#endif
|
||
|
||
float *outputBuffer = (float *)outputLayersInfo[0].buffer;
|
||
(void)outputBuffer;
|
||
// NvDsInferDims dims = outputLayersInfo[0].inferDims;
|
||
|
||
for (size_t jkl = 0; jkl < outputLayersInfo.size(); jkl++) {
|
||
const NvDsInferLayerInfo &layer = outputLayersInfo[jkl];
|
||
|
||
unsigned int numDims = layer.inferDims.numDims;
|
||
unsigned int numElements = layer.inferDims.numElements;
|
||
(void)numElements;
|
||
(void)numDims;
|
||
|
||
// std::cout << "Layer " << jkl << " (" << layer.layerName <<
|
||
// "):\n"; std::cout << " Num Dims: " << numDims << "\n";
|
||
// std::cout << " Num Elements: " << numElements << "\n";
|
||
// std::cout << " Dims: [";
|
||
// for (unsigned int mno = 0; mno < numDims; ++mno) {
|
||
// std::cout << layer.inferDims.d[mno];
|
||
// // layer.inferDims.d[0] = MAX_BODY_PER_FRAME;
|
||
// // layer.inferDims.d[1] = BODY_TENSOR_SIZE;
|
||
// if (mno < numDims - 1)
|
||
// std::cout << ", ";
|
||
// }
|
||
// std::cout << "]\n";
|
||
}
|
||
const NvDsInferLayerInfo &layer = outputLayersInfo[0]; // or loop over all
|
||
|
||
uint detected_persons = 0;
|
||
float *data = static_cast<float *>(layer.buffer);
|
||
for (unsigned int jkl = 0; jkl < MAX_BODY_PER_FRAME; jkl++) {
|
||
if (data[jkl * BODY_TENSOR_SIZE + 4] > threshold_body_detection) {
|
||
detected_persons++;
|
||
}
|
||
}
|
||
update_frame_with_face_body_meta(detected_persons, batch_meta, data,
|
||
frame_meta);
|
||
return detected_persons;
|
||
}
|
||
|
||
void NvInferServerManager::update_frame_with_face_body_meta(
|
||
uint detected_persons, NvDsBatchMeta *batch_meta, float *data,
|
||
NvDsFrameMeta *frame_meta) {
|
||
for (uint index = 0; index < detected_persons; index++) {
|
||
// imprecise_face_obj_meta is the imprecise face
|
||
NvDsObjectMeta *imprecise_face_obj_meta =
|
||
nvds_acquire_obj_meta_from_pool(batch_meta);
|
||
|
||
// meta->unique_id in NvDsInferTensorMeta
|
||
// This is the unique ID of the inference component (PGIE/SGIE)
|
||
// that produced the tensor output. It comes directly from the
|
||
// unique-id property in the [property] section of your
|
||
// config_infer_primary.txt or config_infer_secondary.txt. A
|
||
// pipeline can have multiple inference components (1 PGIE +
|
||
// many SGIEs). Each inference element might output tensors
|
||
// (NvDsInferTensorMeta) that are attached as user metadata.
|
||
// unique_id lets you know which inference element the tensor
|
||
// belongs to. meta->unique_id → The unique-id you assigned in
|
||
// the config for the inference component that produced these
|
||
// tensor outputs.
|
||
|
||
strncpy(imprecise_face_obj_meta->obj_label, imprecise_face_str[0],
|
||
sizeof(imprecise_face_obj_meta->obj_label) - 1);
|
||
imprecise_face_obj_meta
|
||
->obj_label[sizeof(imprecise_face_obj_meta->obj_label) - 1] =
|
||
'\0'; // Ensure null-termination
|
||
imprecise_face_obj_meta->unique_component_id =
|
||
IMPRECISE_FACE_COMPONENT_ID; // meta->unique_id
|
||
|
||
// imprecise_face_obj_meta->unique_component_id
|
||
// Meaning: The ID of the component (PGIE, SGIE, Tracker,
|
||
// Custom, etc.) that generated this metadata. Source: Assigned
|
||
// by DeepStream when metadata is attached by a specific element
|
||
// in the pipeline. Example: PGIE might be assigned
|
||
// unique_component_id = 1 SGIE might be assigned
|
||
// unique_component_id = 2 Tracker usually doesn’t overwrite
|
||
// PGIE’s class_id but may extend metadata (like assigning
|
||
// object_id). You normally don’t set this manually. DeepStream
|
||
// sets it when a particular component (PGIE/SGIE) attaches
|
||
// object metadata. You might override it only if you’re
|
||
// injecting your own custom objects into the pipeline and need
|
||
// to differentiate your component from PGIE/SGIE.
|
||
|
||
imprecise_face_obj_meta->confidence =
|
||
data[index * BODY_TENSOR_SIZE + 4];
|
||
// imprecise_face_obj_meta->object_id = UNTRACKED_OBJECT_ID;
|
||
imprecise_face_obj_meta->class_id =
|
||
IMPRECISE_FACE_CLASS_ID; // 0 for body detection
|
||
NvOSD_RectParams &rect_params_imprecise_face =
|
||
imprecise_face_obj_meta->rect_params;
|
||
NvOSD_TextParams &text_params_imprecise_face =
|
||
imprecise_face_obj_meta->text_params;
|
||
/* Assign bounding box coordinates. */
|
||
rect_params_imprecise_face.left = (data[index * BODY_TENSOR_SIZE + 0] *
|
||
MUXER_OUTPUT_WIDTH / PGIE_NET_WIDTH);
|
||
rect_params_imprecise_face.top =
|
||
(data[index * BODY_TENSOR_SIZE + 1] * MUXER_OUTPUT_HEIGHT /
|
||
PGIE_NET_HEIGHT);
|
||
Point2D left_down_shoulder =
|
||
find_left_down_corner_shoulder(data, index);
|
||
rect_params_imprecise_face.width =
|
||
((left_down_shoulder.x - data[index * BODY_TENSOR_SIZE + 0]) *
|
||
MUXER_OUTPUT_WIDTH / PGIE_NET_WIDTH);
|
||
rect_params_imprecise_face.height =
|
||
((left_down_shoulder.y - data[index * BODY_TENSOR_SIZE + 1]) *
|
||
MUXER_OUTPUT_HEIGHT / PGIE_NET_HEIGHT);
|
||
|
||
clamp_rect_params(frame_meta, &rect_params_imprecise_face, "FACE");
|
||
|
||
/* Border of width 3. */
|
||
rect_params_imprecise_face.border_width = 3;
|
||
rect_params_imprecise_face.has_bg_color = 0;
|
||
rect_params_imprecise_face.border_color =
|
||
NvOSD_ColorParams{0, 0, 1, 1}; // Blue box
|
||
/* display_text requires heap allocated memory. */
|
||
text_params_imprecise_face.display_text =
|
||
g_strdup(imprecise_face_str[0]); // g_strdup(pgie_class_str[0]);
|
||
/* Display text above the left top corner of the object. */
|
||
text_params_imprecise_face.x_offset =
|
||
(rect_params_imprecise_face.left - 15 < 0)
|
||
? 15
|
||
: rect_params_imprecise_face.left - 15;
|
||
text_params_imprecise_face.y_offset =
|
||
(rect_params_imprecise_face.top - 15 < 0)
|
||
? 15
|
||
: rect_params_imprecise_face.top - 15;
|
||
/* Set black background for the text. */
|
||
text_params_imprecise_face.set_bg_clr = 1;
|
||
text_params_imprecise_face.text_bg_clr = NvOSD_ColorParams{0, 0, 0, 1};
|
||
/* Font face, size and color. */
|
||
text_params_imprecise_face.font_params.font_name = (gchar *)"Serif";
|
||
text_params_imprecise_face.font_params.font_size = 11;
|
||
text_params_imprecise_face.font_params.font_color =
|
||
NvOSD_ColorParams{1, 1, 1, 1};
|
||
// adding landmarks to imprecise_face_obj_meta as user_meta
|
||
NvDsUserMeta *um1 = nvds_acquire_user_meta_from_pool(batch_meta);
|
||
assert(um1 != NULL);
|
||
|
||
um1->user_meta_data = set_metadata_ptr(
|
||
&(data[index * BODY_TENSOR_SIZE])); // Add landmarks here
|
||
|
||
um1->base_meta.meta_type =
|
||
NVDS_USER_OBJECT_META_LANDMARKS_AND_SOURCE_ID;
|
||
um1->base_meta.copy_func = (NvDsMetaCopyFunc)copy_user_meta;
|
||
um1->base_meta.release_func = (NvDsMetaReleaseFunc)release_user_meta;
|
||
nvds_add_user_meta_to_obj(imprecise_face_obj_meta, um1);
|
||
nvds_add_obj_meta_to_frame(frame_meta, imprecise_face_obj_meta, NULL);
|
||
|
||
NvDsObjectMeta *body_obj_meta =
|
||
nvds_acquire_obj_meta_from_pool(batch_meta);
|
||
|
||
strncpy(body_obj_meta->obj_label, pgie_class_str[0],
|
||
sizeof(body_obj_meta->obj_label) - 1);
|
||
body_obj_meta->obj_label[sizeof(body_obj_meta->obj_label) - 1] =
|
||
'\0'; // Ensure null-termination
|
||
body_obj_meta->unique_component_id =
|
||
BODY_COMPONENT_ID; // meta->unique_id;
|
||
body_obj_meta->confidence = data[index * BODY_TENSOR_SIZE + 4];
|
||
// body_obj_meta->object_id = UNTRACKED_OBJECT_ID;
|
||
body_obj_meta->class_id = PGIE_CLASS_ID_PERSON; // 0 for body detection
|
||
NvOSD_RectParams &rect_params_body = body_obj_meta->rect_params;
|
||
NvOSD_TextParams &text_params_body = body_obj_meta->text_params;
|
||
/* Assign bounding box coordinates. */
|
||
rect_params_body.left = (data[index * BODY_TENSOR_SIZE + 0] *
|
||
MUXER_OUTPUT_WIDTH / PGIE_NET_WIDTH);
|
||
rect_params_body.top = (data[index * BODY_TENSOR_SIZE + 1] *
|
||
MUXER_OUTPUT_HEIGHT / PGIE_NET_HEIGHT);
|
||
rect_params_body.width = ((data[index * BODY_TENSOR_SIZE + 2] -
|
||
data[index * BODY_TENSOR_SIZE + 0]) *
|
||
MUXER_OUTPUT_WIDTH / PGIE_NET_WIDTH);
|
||
rect_params_body.height = ((data[index * BODY_TENSOR_SIZE + 3] -
|
||
data[index * BODY_TENSOR_SIZE + 1]) *
|
||
MUXER_OUTPUT_HEIGHT / PGIE_NET_HEIGHT);
|
||
|
||
clamp_rect_params(frame_meta, &rect_params_body, "BODY");
|
||
|
||
/* Border of width 3. */
|
||
rect_params_body.border_width = 3;
|
||
rect_params_body.has_bg_color = 0;
|
||
rect_params_body.border_color =
|
||
NvOSD_ColorParams{1, 0, 0, 1}; // Red box
|
||
/* display_text requires heap allocated memory. */
|
||
text_params_body.display_text = g_strdup(pgie_class_str[0]);
|
||
// text_params.display_text = g_strdup_printf("ImpreciseFace %lu",
|
||
// face_obj->object_id);
|
||
/* Display text above the left top corner of the object. */
|
||
text_params_body.x_offset =
|
||
(rect_params_body.left - 30 < 0) ? 10 : rect_params_body.left - 30;
|
||
text_params_body.y_offset =
|
||
(rect_params_body.top - 30 < 0) ? 10 : rect_params_body.top - 30;
|
||
|
||
/* Set black background for the text. */
|
||
text_params_body.set_bg_clr = 1;
|
||
text_params_body.text_bg_clr = NvOSD_ColorParams{0, 0, 0, 1};
|
||
/* Font face, size and color. */
|
||
text_params_body.font_params.font_name = (gchar *)"Serif";
|
||
text_params_body.font_params.font_size = 11;
|
||
text_params_body.font_params.font_color = NvOSD_ColorParams{1, 1, 1, 1};
|
||
// // adding landmarks to body_obj_meta as user_meta
|
||
// NvDsUserMeta *um1 =
|
||
// nvds_acquire_user_meta_from_pool(batch_meta);
|
||
// um1->user_meta_data = set_metadata_ptr(
|
||
// &(data[index * BODY_TENSOR_SIZE])); // Add landmarks here
|
||
// um1->base_meta.meta_type =
|
||
// NVDS_USER_OBJECT_META_LANDMARKS_AND_SOURCE_ID;
|
||
// um1->base_meta.copy_func = (NvDsMetaCopyFunc)copy_user_meta;
|
||
// um1->base_meta.release_func =
|
||
// (NvDsMetaReleaseFunc)release_user_meta;
|
||
// nvds_add_user_meta_to_obj(body_obj_meta, um1);
|
||
nvds_add_obj_meta_to_frame(frame_meta, body_obj_meta, NULL);
|
||
}
|
||
}
|
||
|
||
void NvInferServerManager::clamp_rect_params(NvDsFrameMeta *frame_meta,
|
||
NvOSD_RectParams *rect_params,
|
||
std::string type) {
|
||
(void)type;
|
||
guint frame_width = frame_meta->source_frame_width;
|
||
guint frame_height = frame_meta->source_frame_height;
|
||
|
||
// read values (DeepStream stores rect params as floats)
|
||
float left = rect_params->left;
|
||
float top = rect_params->top;
|
||
float width = rect_params->width;
|
||
float height = rect_params->height;
|
||
float right = left + width;
|
||
float bottom = top + height;
|
||
|
||
// CHECK for invalid numbers (NaN/inf) or out-of-bounds
|
||
bool invalid = false;
|
||
if (!std::isfinite(left) || !std::isfinite(top) || !std::isfinite(width) ||
|
||
!std::isfinite(height)) {
|
||
invalid = true;
|
||
} else if (width <= 0.0f || height <= 0.0f) {
|
||
invalid = true;
|
||
}
|
||
|
||
// clamp coordinates into frame (clip)
|
||
float clamped_left =
|
||
std::max(0.0f, std::min(left, (float)frame_width - 1.0f));
|
||
float clamped_top =
|
||
std::max(0.0f, std::min(top, (float)frame_height - 1.0f));
|
||
float clamped_right = abs(std::min(right, (float)frame_width - 1.0f));
|
||
float clamped_bottom = abs(std::min(bottom, (float)frame_height - 1.0f));
|
||
|
||
float clamped_w = clamped_right - clamped_left;
|
||
float clamped_h = clamped_bottom - clamped_top;
|
||
if (clamped_w <= 0.0f || clamped_h <= 0.0f) {
|
||
invalid = true;
|
||
}
|
||
(void)invalid;
|
||
|
||
rect_params->left = clamped_left;
|
||
rect_params->top = clamped_top;
|
||
rect_params->width = clamped_w;
|
||
rect_params->height = clamped_h;
|
||
return;
|
||
}
|
||
|
||
NvInferServerManager::Point2D
|
||
NvInferServerManager::find_left_down_corner_shoulder(float *data, uint index) {
|
||
Point2D left_down_shoulder;
|
||
// rightmost shoulder point in the BODY!
|
||
if (data[index * BODY_TENSOR_SIZE + 21] >
|
||
data[index * BODY_TENSOR_SIZE + 24]) {
|
||
left_down_shoulder.x = data[index * BODY_TENSOR_SIZE + 21];
|
||
left_down_shoulder.y = data[index * BODY_TENSOR_SIZE + 22];
|
||
} else {
|
||
left_down_shoulder.x = data[index * BODY_TENSOR_SIZE + 24];
|
||
left_down_shoulder.y = data[index * BODY_TENSOR_SIZE + 25];
|
||
}
|
||
return left_down_shoulder;
|
||
}
|
||
|
||
// add custom infromation to metadata by: set_metadata_ptr, copy_user_meta,
|
||
// release_user_meta
|
||
void *NvInferServerManager::set_metadata_ptr(float *arr) {
|
||
float *user_metadata = (float *)g_malloc0(BODY_TENSOR_SIZE * sizeof(float));
|
||
std::memcpy(user_metadata, &arr[0], BODY_TENSOR_SIZE * sizeof(float));
|
||
return (void *)user_metadata;
|
||
}
|
||
|
||
gpointer NvInferServerManager::copy_user_meta(gpointer data,
|
||
gpointer user_data) {
|
||
(void)user_data;
|
||
NvDsUserMeta *user_meta = (NvDsUserMeta *)data;
|
||
gfloat *src_user_metadata = (gfloat *)user_meta->user_meta_data;
|
||
gfloat *dst_user_metadata =
|
||
(gfloat *)g_malloc0(BODY_TENSOR_SIZE * sizeof(gfloat));
|
||
memcpy(dst_user_metadata, src_user_metadata,
|
||
BODY_TENSOR_SIZE * sizeof(gfloat));
|
||
return (gpointer)dst_user_metadata;
|
||
}
|
||
|
||
void NvInferServerManager::release_user_meta(gpointer data,
|
||
gpointer user_data) {
|
||
(void)user_data;
|
||
NvDsUserMeta *user_meta = (NvDsUserMeta *)data;
|
||
if (user_meta->user_meta_data) {
|
||
g_free(user_meta->user_meta_data);
|
||
user_meta->user_meta_data = NULL;
|
||
}
|
||
} |