← 返回博客

狗叫声识别:嵌入式离线犬吠检测 SDK 与分级告警新增

狗叫声识别的价值(场景、流程)

在门口与院落的声音世界里,犬吠是信息量最高、也最含糊的声音。狗对陌生人警戒吠叫、对路过车辆随意吠叫、独自在家持续吠叫——是三种完全不同的含义。检测到犬吠只是第一步,分辨哪种犬吠才是产品价值所在。

智能门铃的经典问题:运动检测分不清"有人到访"和"有车经过",所有触发长得都一样,用户很快陷入告警疲劳。加入狗叫声识别就补上了缺失的上下文:

陌生人到访 — ——运动 + 警戒吠叫 + 人形 → 高优先级告警

路过干扰 — ——随意吠叫、门口无人 → 静默记录

宠物独处 — ——离家期间持续吠叫 → 宠物状态提醒

门口与院落场景
门铃、户外摄像头、宠物看护与社区管理共用一套引擎

犬吠的特点(时域与频域)

犬吠与鸟叫、汽车声对比
成串爆发 vs 高频啄式脉冲 vs 持续长音

下图为一条真实犬吠音频——上为波形图、下为梅尔频谱图,成串爆发的脉冲结构清晰可见:

真实狗叫声:波形与频谱
真实狗叫声示例:波形(上)+ 梅尔频谱(下)

试听素材(真实样本,点击播放):

🔊 真实狗叫声样本

🔊 另一段犬吠样本

成串爆发 — ——单次吠声约 0.2–0.5 秒,通常连续几声成组出现,而不是孤立的单声

中频能量集中 — ——能量带分布在数百 Hz 到数 kHz 之间:低于汽车轰鸣、高于鸟鸣

跨犬种差异大 — ——大型犬低沉浑厚,小型犬尖细急促;检测需要兼顾"同一事件、不同音色"

识别方法:预处理 → 特征提取 → 算法

引擎走标准管线(降噪 → 分帧 → 时频特征),并叠加犬吠专属的设计选择:

1. 以"串"为单位——先定位每次爆发,再验证成串结构:连续多次爆发且间隔符合吠叫节奏才算犬吠事件。孤立的突发声(关门、物体掉落)不轻易判定

2. 跨犬种与跨类别泛化——训练覆盖不同体型犬只音色,同时对鸟叫、猫叫、人声、车声等"近邻类别"施加高区分度约束

3. 户外鲁棒性——事件化检测对风噪、雨声等持续性噪声天然不敏感

端侧系统结构
采集、处理、引擎、输出、应用

分级告警:把"听到狗叫"变成有用的信息

犬吠分级告警流程
人形联动、持续时长判断与三级输出

1. 犬吠事件——成串验证通过

2. 场景判定——是否检测到人形/访客?吠叫是否持续?

3. 分级输出——高优先级告警(推送 + 录像 + 双向对讲)/ 静默记录 / 宠物状态提醒

全部判定在设备端完成,分级策略可按客户业务配置。

难点所在

狗叫声识别要在拥挤的声场中把自己摘出来:鸟叫(高频)、猫叫(近邻)、人声与车流(干扰源)。远距离衰减与户外风噪雨声再叠加物理难度。应对方式是同一套:多类别负样本训练 + 事件聚合——这也是真实院落中误报率能控制在 2% 以下的原因。

准确率与性能

狗叫声识别性能数据
不同距离与环境的识别表现(示意)

在 0.5–10 米的常用门口距离内,安静与嘈杂环境下均保持稳定识别。主要误报来源是"像犬吠的人声与车流"——多类别负样本训练把误报率压到 2% 以下。

项目
指标
准确率
96.0%
误报率
<2%
模型大小
0.2–1MB(INT8)
推理延迟
灵活可调(视平台资源)
采样率
16kHz
支持平台
ARM Linux / MIPS / x86_64;SVP / Magik 预适配

注:文中性能指标基于内部测试环境,实际表现取决于硬件配置与使用场景。

应用形态

智能门铃(犬吠 + 人形联动)、户外摄像头(院落监测与夜间异常辅助)、宠物看护(独处吠叫记录)、社区管理(公共区域吠叫事件)——同一套引擎,按场景配置。

运行平台与硬件要求

模型适配门铃级 SoC:0.2–1MB(INT8)、CPU 占用低于 50MHz,与视频编码、网络传输共享 SoC 资源。

C 接口与嵌入式集成

「狗叫声」识别库提供简洁的流式 C 接口:调用方只需持续送入 16kHz 单声道 PCM,拼帧、Mel 预处理与模型推理全部在内部完成,帧级概率经报警策略聚合成「狗叫事件」回调输出。

完整接口声明(bark_detect.h):

bark_detect.hc
/**
 * bark_detect.h — 狗叫声识别统一接口
 *
 * 封装 Mel 预处理 + 推理引擎 + 报警策略, 内部模型消费线程处理音频。
 * 与录音模块 (audio_capture.h) 相互独立: 调用者自行决定音频来源
 * (录音回调 / wav 文件 / 网络流), 通过 bark_detect_feed 送入, 数据任意大小。
 *
 * 用法 (实时录音模式):
 *   bark_detect_t *d = bark_detect_create(mgk_path, NULL, NULL);
 *   bark_detect_set_listener(d, on_frame, on_onset, on_offset, NULL);
 *   bark_detect_start(d);                          // 启动内部模型消费线程
 *   audio_capture_start(rec, capture_cb, d);        // 录音回调里调 bark_detect_feed
 *   ...
 *   bark_detect_stop(d);                           // 排空缓冲, 停止线程
 *   bark_detect_destroy(d);
 *
 * 用法 (wav 文件模式):
 *   bark_detect_t *d = bark_detect_create(mgk_path, NULL, NULL);
 *   bark_detect_set_listener(d, on_frame, on_onset, on_offset, NULL);
 *   bark_detect_start(d);
 *   循环读文件: bark_detect_feed(d, pcm, n);       // 任意数据大小
 *   bark_detect_stop(d);
 *   bark_detect_destroy(d);
 */

#ifndef BARK_DETECT_H
#define BARK_DETECT_H

#include <stdint.h>

#ifdef __cplusplus
extern "C" {
#endif

/* 识别事件 (报警策略输出, 用于事件结束回调) */
typedef struct {
    float start_time;       /* 事件开始时间 (秒) */
    float end_time;         /* 事件结束时间 (秒) */
    float confidence;       /* 事件置信度 */
    float max_confidence;   /* 事件内最大帧置信度 */
    int   frame_count;      /* 事件持续帧数 */
} bark_detect_event_t;

/* 帧级回调: 每帧识别结果 (模型线程内执行) */
typedef void (*bark_detect_frame_cb_t)(float bark_prob, float timestamp,
                                        void *user_data);

/* 事件开始回调: 策略判定狗叫事件开始, 只有开始时间 */
typedef void (*bark_detect_onset_cb_t)(float start_time, void *user_data);

/* 事件结束回调: 策略判定狗叫事件结束 (或停止识别时未结束的事件), 完整事件信息 */
typedef void (*bark_detect_offset_cb_t)(const bark_detect_event_t *event,
                                         void *user_data);

typedef struct bark_detect_s bark_detect_t;

/* 创建/销毁; alarm_name/alarm_params 可传 NULL (用默认策略及参数) */
bark_detect_t *bark_detect_create(const char *mgk_path,      /* 模型文件路径 (必填) */
                                    const char *alarm_name,    /* 报警策略名, NULL=默认 */
                                    const char *alarm_params); /* 策略参数 key=val,key=val, NULL=默认 */
void bark_detect_destroy(bark_detect_t *det);

/* 设置事件回调 (create 后调用, 也可在运行中调整); 不需要的回调传 NULL */
void bark_detect_set_listener(bark_detect_t *det,
                               bark_detect_frame_cb_t  on_frame,
                               bark_detect_onset_cb_t  on_onset,
                               bark_detect_offset_cb_t on_offset,
                               void *user_data);

/* 启动/停止识别: 启动内部模型消费线程 / 排空缓冲后停止线程 */
int  bark_detect_start(bark_detect_t *det);
void bark_detect_stop(bark_detect_t *det);
int  bark_detect_is_running(bark_detect_t *det);

/* 设置事件识别策略 (可在运行中调整) */
int bark_detect_set_alarm(bark_detect_t *det, const char *alarm_name,
                           const char *alarm_params);

/* 送入 PCM 数据 (16bit 单声道 16kHz), 线程安全, 任意数据大小 */
int bark_detect_feed(bark_detect_t *det, const int16_t *pcm, int num_samples);

#ifdef __cplusplus
}
#endif

#endif /* BARK_DETECT_H */

最简 wav 推理示例(节选,完整文件位于 SDK 的 src/barkDetect/c/bark_demo.c):

bark_demo.cc
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include "bark_detect.h"

#define DEFAULT_MGK  "bark_detect_v7.mgk"  /* 模型文件 */
#define DEFAULT_WAV  "test_bark.wav"       /* 16kHz 单声道 16bit PCM */
#define FEED_CHUNK   16000                  /* 每次送入 1 秒音频 */

/* 帧级回调: 每帧输出狗叫声概率 (约 1 秒一帧) */
static void on_frame(float bark_prob, float timestamp, void *user_data)
{
    (void)user_data;
    printf("%8.2fs  bark=%.4f\n", timestamp, bark_prob);
}

/* 事件开始回调: 策略判定狗叫事件开始 */
static void on_onset(float start_time, void *user_data)
{
    (void)user_data;
    printf("[EVENT] bark start at %.2fs\n", start_time);
}

/* 事件结束回调: 应用层可据此做后续统计或分级响应 */
static void on_offset(const bark_detect_event_t *ev, void *user_data)
{
    (void)user_data;
    printf("[EVENT] bark end at %.2fs (dur=%.2fs, conf=%.3f, frames=%d)\n",
           ev->end_time, ev->end_time - ev->start_time,
           ev->confidence, ev->frame_count);
}

static int read_wav_pcm(const char *path, int16_t **pcm, int *n, int *sr);  /* 完整实现见源文件 */

int main(void)
{
    bark_detect_t *det;
    int16_t *pcm = NULL;
    int num_samples = 0, sample_rate = 0;
    int pos;

    if (read_wav_pcm(DEFAULT_WAV, &pcm, &num_samples, &sample_rate) != 0)
        return 1;

    /* 1. 创建识别器: 模型文件 + 默认报警策略 (NULL) */
    det = bark_detect_create(DEFAULT_MGK, NULL, NULL);
    if (!det) return 1;

    /* 2. 注册回调 (均为可选) */
    bark_detect_set_listener(det, on_frame, on_onset, on_offset, NULL);

    /* 3. 启动内部模型消费线程 */
    bark_detect_start(det);

    /* 4. 分块送入 PCM; 实时录音时改在录音回调里 feed */
    for (pos = 0; pos < num_samples; pos += FEED_CHUNK) {
        int n = num_samples - pos;
        if (n > FEED_CHUNK) n = FEED_CHUNK;
        bark_detect_feed(det, pcm + pos, n);
    }

    /* 5. 停止并销毁 */
    bark_detect_stop(det);
    bark_detect_destroy(det);
    free(pcm);
    return 0;
}

编译与运行(示例):

buildbash
$(CC) bark_demo.c -I. -L. -lbarkdetect -lpthread -lm -o bark_demo
./bark_demo

结语

狗叫声识别的价值不在"检测到狗叫",而在理解"这次吠叫意味着什么"。我们提供在线试用与完整的技术支持。