grid_record: добавить --yw-mqtt + --yw-topic для magenta bbox от YOLO-World
Параллельный MQTT subscriber на отдельный topic (default yoloworld/events)
от yolo-world-detector сервиса. Использует те же --detection-cell что
Frigate, но рендерит bbox magenta цветом (Y=105 U=212 V=234) вместо
зелёного (Y=210 U=50 V=100).
На одной картинке композитор может одновременно показать:
- зелёный bbox от Frigate (person/car/...)
- magenta bbox от yolo-world (fox/dog/drone/...)
Backward compat 100% — без --yw-mqtt никаких изменений в поведении.
Архитектурно:
- Второй cfc_frigate_mqtt_t (тот же envelope schema через
cfc_frigate_mqtt parser — yolo-world-detector публикует
Frigate-compat events)
- Параллельный yw_detbox_overlays[] с magenta colors
- yolo-world subscriber не управляет motion-layout (composer=NULL),
только Frigate шлёт motion-pulse'ы
Verify build:
cmake --build build # все 4 target'а (grid_record, simple_record,
# grid_record_cpp, cuframes_composer_static)
Live test пока через docker recreate в Phase 5 deploy, после того
как yolo-world publish'ит в реальный MQTT.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
+85
-1
@@ -127,6 +127,12 @@ int main(int argc, char **argv)
|
||||
const char *frigate_mqtt_host = NULL;
|
||||
int frigate_mqtt_port = 1883;
|
||||
const char *frigate_topic = "frigate/events";
|
||||
/* YOLO-World subscriber (Phase 3 yolo-world-detector) — параллельный
|
||||
* detection-overlay поток. Использует те же detection-cells что и
|
||||
* Frigate, но рендерит bbox magenta цветом. По умолчанию выключен. */
|
||||
const char *yw_mqtt_host = NULL;
|
||||
int yw_mqtt_port = 1883;
|
||||
const char *yw_topic = "yoloworld/events";
|
||||
const char *mqtt_overlays_path = NULL; /* JSON-конфиг MQTT-driven text overlays */
|
||||
const char *initial_layout = NULL; /* --layout NAME → set_layout после init */
|
||||
int motion_mode = 0; /* --motion-mode */
|
||||
@@ -174,6 +180,8 @@ int main(int argc, char **argv)
|
||||
{"audio-source", required_argument, 0, 'A'}, /* RTSP audio URL */
|
||||
{"frigate-mqtt", required_argument, 0, 'G'}, /* host[:port] */
|
||||
{"frigate-topic", required_argument, 0, 'T'},
|
||||
{"yw-mqtt", required_argument, 0, 'Y'}, /* host[:port] для yolo-world detector */
|
||||
{"yw-topic", required_argument, 0, 'Q'},
|
||||
{"detection-cell", required_argument, 0, 'D'},
|
||||
{"layout", required_argument, 0, 'L'}, /* named layout (quad, single, ...) */
|
||||
{"source", required_argument, 0, 'S'}, /* pool source: key,frigate=...,priority=N */
|
||||
@@ -185,7 +193,7 @@ int main(int argc, char **argv)
|
||||
};
|
||||
const char *templates_path = NULL;
|
||||
int c;
|
||||
while ((c = getopt_long(argc, argv, "o:c:f:b:W:H:s:r:i:t:C:M:I:U:P:RF:A:G:T:D:L:S:mk:z:x:", opts, NULL)) != -1) {
|
||||
while ((c = getopt_long(argc, argv, "o:c:f:b:W:H:s:r:i:t:C:M:I:U:P:RF:A:G:T:Y:Q:D:L:S:mk:z:x:", opts, NULL)) != -1) {
|
||||
switch (c) {
|
||||
case 'o': out_path = optarg; break;
|
||||
case 'c':
|
||||
@@ -239,6 +247,21 @@ int main(int argc, char **argv)
|
||||
break;
|
||||
}
|
||||
case 'T': frigate_topic = optarg; break;
|
||||
case 'Y': {
|
||||
yw_mqtt_host = optarg;
|
||||
const char *colon = strchr(optarg, ':');
|
||||
if (colon) {
|
||||
static char yw_host_buf[64];
|
||||
int n = colon - optarg;
|
||||
if (n >= (int)sizeof(yw_host_buf)) n = sizeof(yw_host_buf) - 1;
|
||||
memcpy(yw_host_buf, optarg, n);
|
||||
yw_host_buf[n] = '\0';
|
||||
yw_mqtt_host = yw_host_buf;
|
||||
yw_mqtt_port = atoi(colon + 1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'Q': yw_topic = optarg; break;
|
||||
case 'L': initial_layout = optarg; break;
|
||||
case 'm': motion_mode = 1; break;
|
||||
case 'k': motion_ttl = atoi(optarg); break;
|
||||
@@ -564,6 +587,39 @@ int main(int argc, char **argv)
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
/* YOLO-World detection-box overlays — параллельный набор для второго
|
||||
* subscriber'а. Magenta цвет (BT.709 limited Y=105 U=212 V=234). Те же
|
||||
* detection-cells (camera/zones), но bbox рисуется magenta. На один
|
||||
* frame можно увидеть зелёный bbox от Frigate И magenta от YOLO-World
|
||||
* — если оба детектят. yolo-world-detector публикует в MQTT topic
|
||||
* yoloworld/events/<camera> с Frigate-compat envelope. */
|
||||
cfc_overlay_t *yw_detbox_overlays[MAX_CELLS] = { 0 };
|
||||
if (yw_mqtt_host) {
|
||||
for (int i = 0; i < num_detcells; i++) {
|
||||
cfc_overlay_detbox_config_t yc = {
|
||||
.camera_key = detcells[i].camera,
|
||||
.detect_w = detcells[i].detect_w,
|
||||
.detect_h = detcells[i].detect_h,
|
||||
.cell_x = detcells[i].dx, .cell_y = detcells[i].dy,
|
||||
.cell_w = detcells[i].dw, .cell_h = detcells[i].dh,
|
||||
.thickness = 6,
|
||||
.color_y = 105, .color_u = 212, .color_v = 234, /* magenta */
|
||||
.alpha = 240,
|
||||
.stale_ms = 8000,
|
||||
.required_zones = detcells[i].num_zones ? detcells[i].zone_ptrs : NULL,
|
||||
.required_zones_count = detcells[i].num_zones,
|
||||
};
|
||||
if (cfc_overlay_create_detection_boxes(&yc, &yw_detbox_overlays[i]) != 0) {
|
||||
fprintf(stderr, "[grid_record] yw detbox create failed для '%s'\n",
|
||||
detcells[i].camera);
|
||||
continue;
|
||||
}
|
||||
cfc_composer_add_overlay(comp, yw_detbox_overlays[i]);
|
||||
fprintf(stderr, "[grid_record] yw detbox '%s' → cell %s (magenta)\n",
|
||||
detcells[i].camera, detcells[i].key);
|
||||
}
|
||||
}
|
||||
|
||||
/* Frigate MQTT subscriber: запускаем если есть detection-cells
|
||||
* (overlay'ные bbox'ы) ИЛИ motion-mode (auto-layout drivers). */
|
||||
cfc_frigate_mqtt_t *frigate = NULL;
|
||||
@@ -586,6 +642,33 @@ int main(int argc, char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
/* YOLO-World MQTT subscriber — параллельный поток detection-events с
|
||||
* yoloworld/events/<camera>. Использует тот же envelope как Frigate
|
||||
* (cfc_frigate_mqtt парсер совместим), но рендерит на yw_detbox_overlays
|
||||
* (magenta). motion-pulse'ы НЕ шлёт (composer NULL), композитор
|
||||
* управляется только Frigate motion-pulse'ами. */
|
||||
cfc_frigate_mqtt_t *yw_mqtt = NULL;
|
||||
if (yw_mqtt_host && num_detcells > 0) {
|
||||
cfc_frigate_mqtt_config_t yc = {
|
||||
.host = yw_mqtt_host, .port = yw_mqtt_port,
|
||||
.username = mqtt_user, .password = mqtt_pass,
|
||||
.topic = yw_topic,
|
||||
.composer = NULL, /* yolo-world не управляет motion-layout */
|
||||
};
|
||||
if (cfc_frigate_mqtt_create(&yc, &yw_mqtt) == 0) {
|
||||
for (int i = 0; i < num_detcells; i++) {
|
||||
if (yw_detbox_overlays[i]) {
|
||||
cfc_frigate_mqtt_register_overlay(yw_mqtt, yw_detbox_overlays[i]);
|
||||
}
|
||||
}
|
||||
cfc_frigate_mqtt_start(yw_mqtt);
|
||||
fprintf(stderr, "[grid_record] yw_mqtt started → %s:%d topic=%s\n",
|
||||
yw_mqtt_host, yw_mqtt_port, yw_topic);
|
||||
} else {
|
||||
fprintf(stderr, "[grid_record] yw_mqtt create failed\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* PNG иконки. */
|
||||
for (int i = 0; i < num_icons; i++) {
|
||||
cfc_overlay_png_config_t pc = {
|
||||
@@ -795,6 +878,7 @@ int main(int argc, char **argv)
|
||||
|
||||
cfc_writer_close(wctx.writer);
|
||||
if (frigate) cfc_frigate_mqtt_destroy(frigate);
|
||||
if (yw_mqtt) cfc_frigate_mqtt_destroy(yw_mqtt);
|
||||
if (audio) cfc_audio_destroy(audio);
|
||||
if (ctl) cfc_control_destroy(ctl);
|
||||
if (hpub) cfc_health_destroy(hpub);
|
||||
|
||||
Reference in New Issue
Block a user