Skip to content

Commit f396808

Browse files
committed
[GST gvawatermark] Add inclusive/exclusive label filtering
Implement object label filtering functionality that allows users to control which detected objects are highlighted with watermark based on their classification labels. - Add include-labels and exclude-labels parameters to displ-cfg - Support colon-delimited label specification (e.g., "person:car:bicycle") - Precedence logic where inclusion filters above exclusion filters - Add parseFilterConfig utility function for label parsing - Update documentation with filtering parameter usage examples Signed-off-by: Walid <walid.aly@intel.com>
1 parent 6a98e8b commit f396808

File tree

7 files changed

+128
-40
lines changed

7 files changed

+128
-40
lines changed
229 KB
Loading
1.18 MB
Loading

docs/source/elements/gvawatermark.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,30 @@ Controls the size of text labels displayed on detected objects.
151151
152152
*Displays average FPS counter when `gvafpscounter` element is present in pipeline*
153153
154+
### Label Filtering
155+
156+
You can selectively show or hide detected objects based on their labels using filtering parameters:
157+
158+
**Include Labels (`show-labels=person:car:truck`)**
159+
- Only objects with labels "person", "car", or "truck" will be displayed
160+
- All other detected objects will be hidden
161+
- Useful for focusing on specific object types
162+
163+
e.g `displ-cfg=show-labels=car`
164+
![Car label included](../_images/roi-include-car.png)
165+
166+
**Exclude Labels (`hide-labels=bottle:cup:laptop`)**
167+
- Objects with labels "bottle", "cup", or "laptop" will be hidden
168+
- All other detected objects will be displayed
169+
- Useful for removing distracting or irrelevant objects from the display
170+
171+
e.g `displ-cfg=hide-labels=car`
172+
![Car label excluded](../_images/roi-exclude-car.png)
173+
174+
**Filter Priority**
175+
- If both `show-labels` and `hide-labels` are specified, `show-labels` takes precedence
176+
- Empty lists mean no filtering is applied
177+
154178
### Configuration Examples
155179
156180
```bash
@@ -165,4 +189,13 @@ displ-cfg=color-idx=0,thickness=1,font-type=simplex
165189

166190
# Complete custom styling
167191
displ-cfg=font-scale=1.5,thickness=3,color-idx=2,font-type=complex,draw-txt-bg=true
192+
193+
# Show only specific object types
194+
displ-cfg=show-labels=person:car:truck
195+
196+
# Hide specific object types
197+
displ-cfg=hide-labels=bottle:cup:laptop
198+
199+
# Combine filtering with styling
200+
displ-cfg=show-labels=person:car,font-scale=1.2,color-idx=1
168201
```

src/monolithic/gst/elements/gvawatermark/gstgvawatermarkimpl.cpp

Lines changed: 67 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040

4141
#include <array>
4242
#include <exception>
43+
#include <optional>
4344
#include <string>
4445
#include <typeinfo>
4546
#if !defined(ENABLE_VAAPI) || defined(_WIN32)
@@ -146,6 +147,8 @@ struct Impl {
146147
const GVA::Rect<double> &rectangle, std::vector<render::Prim> &prims) const;
147148
void find_gvafpscounter_element();
148149
void parse_displ_config();
150+
inline bool is_ROI_filtered_out(const std::string &label) const;
151+
149152
std::unique_ptr<Renderer> createRenderer(std::shared_ptr<ColorConverter> converter);
150153

151154
std::unique_ptr<Renderer> createGPURenderer(dlstreamer::ImageFormat format,
@@ -192,6 +195,8 @@ struct Impl {
192195
uint thickness = DEFAULT_THICKNESS;
193196
int font_type = cv::FONT_HERSHEY_TRIPLEX;
194197
double font_scale = DEFAULT_TEXT_SCALE;
198+
std::optional<std::unordered_set<std::string>> include_labels_filter;
199+
std::optional<std::unordered_set<std::string>> exclude_labels_filter;
195200
} _displCfg;
196201
};
197202

@@ -899,54 +904,62 @@ bool Impl::render_va(cv::Mat *buffer) {
899904
return true;
900905
}
901906

902-
void Impl::preparePrimsForRoi(GVA::RegionOfInterest &roi, std::vector<render::Prim> &prims) const {
903-
size_t color_index = roi.label_id();
907+
inline bool Impl::is_ROI_filtered_out(const std::string &label) const {
908+
return _displCfg.include_labels_filter.has_value()
909+
? (_displCfg.include_labels_filter->count(label) == 0)
910+
: (_displCfg.exclude_labels_filter.has_value() && _displCfg.exclude_labels_filter->count(label) != 0);
911+
}
904912

905-
auto rect_u32 = roi.rect();
906-
GVA::Rect<double> rect = {safe_convert<double>(rect_u32.x), safe_convert<double>(rect_u32.y),
907-
safe_convert<double>(rect_u32.w), safe_convert<double>(rect_u32.h)};
913+
void Impl::preparePrimsForRoi(GVA::RegionOfInterest &roi, std::vector<render::Prim> &prims) const {
914+
if (!is_ROI_filtered_out(roi.label())) {
915+
size_t color_index = roi.label_id();
908916

909-
clip_rect(rect.x, rect.y, rect.w, rect.h, _vinfo);
917+
auto rect_u32 = roi.rect();
918+
GVA::Rect<double> rect = {safe_convert<double>(rect_u32.x), safe_convert<double>(rect_u32.y),
919+
safe_convert<double>(rect_u32.w), safe_convert<double>(rect_u32.h)};
910920

911-
std::ostringstream text;
912-
const int object_id = roi.object_id();
913-
if (object_id > 0) {
914-
text << object_id << ": ";
915-
color_index = object_id;
916-
}
921+
clip_rect(rect.x, rect.y, rect.w, rect.h, _vinfo);
917922

918-
if (roi.label().size() > 1) {
919-
appendStr(text, roi.label());
920-
text << int(roi.confidence() * 100) << "%";
921-
}
923+
std::ostringstream text;
924+
const int object_id = roi.object_id();
925+
if (object_id > 0) {
926+
text << object_id << ": ";
927+
color_index = object_id;
928+
}
922929

923-
// Prepare primitives for tensors
924-
for (auto &tensor : roi.tensors()) {
925-
preparePrimsForTensor(tensor, rect, prims, color_index);
926-
if (!tensor.is_detection()) {
927-
appendStr(text, tensor.label());
930+
if (roi.label().size() > 1) {
931+
appendStr(text, roi.label());
932+
text << int(roi.confidence() * 100) << "%";
928933
}
929-
}
930934

931-
// set color
932-
Color color = indexToColor(color_index);
933-
if (_displCfg.color_idx != DEFAULT_COLOR_IDX)
934-
color = _default_color;
935-
936-
// put rectangle
937-
cv::Rect bbox_rect(rect.x, rect.y, rect.w, rect.h);
938-
if (!_obb)
939-
prims.emplace_back(render::Rect(bbox_rect, color, _displCfg.thickness, roi.rotation()));
940-
941-
// put text
942-
if (_displCfg.show_labels)
943-
if (text.str().size() != 0) {
944-
cv::Point2f pos(rect.x, rect.y - 5.f);
945-
if (pos.y < 0)
946-
pos.y = rect.y + 30.f;
947-
prims.emplace_back(render::Text(text.str(), pos, _displCfg.font_type, _displCfg.font_scale, color));
935+
// Prepare primitives for tensors
936+
for (auto &tensor : roi.tensors()) {
937+
preparePrimsForTensor(tensor, rect, prims, color_index);
938+
if (!tensor.is_detection()) {
939+
appendStr(text, tensor.label());
940+
}
948941
}
949942

943+
// set color
944+
Color color = indexToColor(color_index);
945+
if (_displCfg.color_idx != DEFAULT_COLOR_IDX)
946+
color = _default_color;
947+
948+
// put rectangle
949+
cv::Rect bbox_rect(rect.x, rect.y, rect.w, rect.h);
950+
if (!_obb)
951+
prims.emplace_back(render::Rect(bbox_rect, color, _displCfg.thickness, roi.rotation()));
952+
953+
// put text
954+
if (_displCfg.show_labels)
955+
if (text.str().size() != 0) {
956+
cv::Point2f pos(rect.x, rect.y - 5.f);
957+
if (pos.y < 0)
958+
pos.y = rect.y + 30.f;
959+
prims.emplace_back(render::Text(text.str(), pos, _displCfg.font_type, _displCfg.font_scale, color));
960+
}
961+
}
962+
950963
// put avg-fps from gvafpscounter element
951964
if (_displ_avgfps) {
952965
std::ostringstream fpstext;
@@ -1222,6 +1235,21 @@ void Impl::parse_displ_config() {
12221235
}
12231236
cfg.erase(iter);
12241237
}
1238+
if (iter = cfg.find("show-labels"); iter != cfg.end()) {
1239+
_displCfg.include_labels_filter = std::unordered_set<std::string>();
1240+
Utils::parseFilterConfig(iter->second, *_displCfg.include_labels_filter);
1241+
cfg.erase(iter);
1242+
}
1243+
if (iter = cfg.find("hide-labels"); iter != cfg.end()) {
1244+
if (_displCfg.include_labels_filter.has_value() && !(_displCfg.include_labels_filter->empty())) {
1245+
GST_WARNING("[gvawatermarkimpl] Both 'show-labels' and 'hide-labels' parameters are set, "
1246+
"'hide-labels' will be ignored.");
1247+
} else {
1248+
_displCfg.exclude_labels_filter = std::unordered_set<std::string>();
1249+
Utils::parseFilterConfig(iter->second, *_displCfg.exclude_labels_filter);
1250+
}
1251+
cfg.erase(iter);
1252+
}
12251253
} catch (...) {
12261254
if (iter == cfg.end())
12271255
std::throw_with_nested(

src/monolithic/gst/elements/gvawatermark/gstgvawatermarkimpl.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,14 @@ enum { PROP_0, PROP_DEVICE, PROP_OBB, PROP_DISPL_AVGFPS, PROP_DISPL_CFG };
8282
"script_simplex, script_complex), default triplex\n" \
8383
"\t\t\tdraw-txt-bg=<bool> enable or disable displaying text labels background, by enabling it the text color " \
8484
"is set to white, default false\n" \
85+
"\t\t\tinclude-labels=<string> colon-separated list of labels to include (only these objects will be shown), " \
86+
"default empty\n" \
87+
"\t\t\texclude-labels=<string> colon-separated list of labels to exclude (these objects will be hidden), default " \
88+
"empty\n" \
8589
"\t\t\te.g.: displ-cfg=show-labels=false\n" \
86-
"\t\t\te.g.: displ-cfg=font-scale=0.5,thickness=3,color-idx=2,font-type=simplex"
90+
"\t\t\te.g.: displ-cfg=font-scale=0.5,thickness=3,color-idx=2,font-type=simplex\n" \
91+
"\t\t\te.g.: displ-cfg=show-labels=person:car:truck\n" \
92+
"\t\t\te.g.: displ-cfg=hide-labels=bottle:cup"
8793

8894
G_END_DECLS
8995

src/utils/utils.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,15 @@ std::vector<std::string> splitString(const std::string &input, char delimiter) {
4646
return tokens;
4747
}
4848

49+
void parseFilterConfig(const std::string &config_str, std::unordered_set<std::string> &filtered_set, char delimiter) {
50+
auto labels = splitString(config_str, delimiter);
51+
for (const auto &label : labels) {
52+
if (filtered_set.count(label) == 0) {
53+
filtered_set.insert(label);
54+
}
55+
}
56+
}
57+
4958
std::map<std::string, std::string> stringToMap(const std::string &s, char rec_delim /*= ','*/,
5059
char kv_delim /*= '='*/) {
5160
std::string key, val;

src/utils/utils.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include <set>
1717
#include <sstream>
1818
#include <string>
19+
#include <unordered_set>
1920
#include <vector>
2021

2122
#ifdef _MSC_VER
@@ -55,6 +56,17 @@ std::string join(Iter begin, Iter end, char delimiter = ',') {
5556
return result.str();
5657
}
5758

59+
/**
60+
* Parses a label filter configuration string in the format `label1:label2:label3:...`.
61+
* Labels values are added to the output set for filtering.
62+
*
63+
* @param config_str The configuration string to parse (e.g., "person:car:bike").
64+
* @param filtered_set Output set that will contain only the relevant labels.
65+
* @param delimiter The delimiter used to separate label entries (default is ':').
66+
*/
67+
void parseFilterConfig(const std::string &config_str, std::unordered_set<std::string> &filtered_set,
68+
char delimiter = ':');
69+
5870
/**
5971
* Converts string in format `key1=val1,key2=val2,...` to key/value pairs.
6072
*

0 commit comments

Comments
 (0)