← 返回博客

尖叫检测:嵌入式离线尖叫识别 SDK 与安全预警新增

尖叫检测的价值(场景、流程)

尖叫是一种有人类独有的声学形态的求助信号——高能量、持续拉高的音高。但它也容易被噪声淹没、容易被歌唱、欢呼与儿童嬉闹混淆。因此检测的本质是证据与区分,而不只是灵敏度。与摄像头不同,麦克风在黑暗中、门后都能工作,而且保护隐私——这对卧室与卫浴附近空间的接受度至关重要。

场景族:家庭安防摄像头、独居监护(联系人链)、夜间公共空间(街道上的安全网)。

独居场景
户内检测与紧急联系人链

尖叫的特点:与说话、歌唱的区分

尖叫与说话、歌唱对比
高能量持续爆发 vs 平缓说话 vs 宽音域旋律

下图为一条真实尖叫音频——上为波形图、下为梅尔频谱图,持续的高能量人声爆发在整个频带上都有显著能量:

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

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

🔊 真实女声尖叫样本

🔊 另一段尖叫样本

能量 — ——响度显著高于同环境的对话基线

音高 — ——保持高位且稳定,是"持续拉高";说话频繁起伏,歌唱在宽音域平滑滑动

时长 — ——尖叫比惊讶的一声"啊"更长;用时长阈值把瞬间惊呼与持续求助分开

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

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

引擎组合能量 + 音高双证据,通过多类别负样本训练区分说话/歌唱/儿童嬉闹,并以相对能量判断让检测不依赖嘈杂环境中的绝对音量。最大混淆源是歌唱——靠"宽音域滑动 vs 持续拉高"区分;单次惊呼低于时长阈值。

检测与联动流程

检测与联动流程
事件验证、持续性分析与场景化联动

单次惊呼记录并普通提醒;持续尖叫进入告警级(推送 + 音频片段,可配置外呼)。联动随场景不同:家居(通知家人 + 画面确认)、独居监护(紧急联系人链)、公共场所(值守中心 + 就近巡逻)。

定位说明:这是加快人工响应的安全辅助工具——真正的紧急情况请直接拨打报警/急救电话。

独居场景:联系人链

分级响应流程
检测、分级、通知、升级与记录

1. 求助声检测——持续尖叫/呼喊在设备端识别

2. 分级判断——强度、持续性、时段

3. 即时通知——紧急联系人(含音频片段)

4. 联系人对讲——通过设备双向对讲确认状况

5. 无响应升级——邻居、物业、社区网格

6. 记录与配置优化——误报复盘、联系人链调整

公共空间:夜间安全网

公共空间场景
路灯杆感知节点与值守中心"先复核再调度"

夜间街道与交通枢纽周边,路灯杆上的感知节点把事件送进值守中心:带点位的事件、自动调取的画面、就近调度的巡逻力量。先复核再调度让资源集中在真实事件上。

公共空间事件数据
时段分布与场景化部署侧重(示意)

事件集中在晚间与夜间;部署侧重随场景不同——安静街道适合放大间距、优先覆盖照明薄弱路段;交通枢纽依靠相对能量判断保持稳定;校园与安保值守流程深度结合,并可复用枪声检测的部署体系。

准确率与性能

环境与区分度数据
不同环境检出率与误报来源(示意)

相对能量判断让检测从安静室内到嘈杂户外保持稳定(示意 92%+)。关键取舍:灵敏度与误报是按场景配置的——独居监护偏"宁可多提醒",公共场景偏"复核优先"。

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

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

运行平台与硬件要求

摄像头与看护设备级 SoC 起;标准模型 CPU 占用低于 50MHz;电池设备可走低功耗常驻架构;隐私敏感场景无需摄像头。

C 接口与嵌入式集成

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

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

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

#ifndef SCREAM_DETECT_H
#define SCREAM_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;      /* 事件持续帧数 */
} scream_detect_event_t;

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

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

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

typedef struct scream_detect_s scream_detect_t;

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

/* 设置事件回调 (create 后调用, 也可在运行中调整); 不需要的回调传 NULL */
void scream_detect_set_listener(scream_detect_t *det,
                               scream_detect_frame_cb_t  on_frame,
                               scream_detect_onset_cb_t  on_onset,
                               scream_detect_offset_cb_t on_offset,
                               void *user_data);

/* 启动/停止识别: 启动内部模型消费线程 / 排空缓冲后停止线程 */
int  scream_detect_start(scream_detect_t *det);
void scream_detect_stop(scream_detect_t *det);
int  scream_detect_is_running(scream_detect_t *det);

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

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

#ifdef __cplusplus
}
#endif

#endif /* SCREAM_DETECT_H */

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

scream_demo.cc
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include "scream_detect.h"

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

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

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

/* 事件结束回调: 应用层可据此做后续统计或分级响应 */
static void on_offset(const scream_detect_event_t *ev, void *user_data)
{
    (void)user_data;
    printf("[EVENT] scream 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)
{
    scream_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 = scream_detect_create(DEFAULT_MGK, NULL, NULL);
    if (!det) return 1;

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

    /* 3. 启动内部模型消费线程 */
    scream_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;
        scream_detect_feed(det, pcm + pos, n);
    }

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

编译与运行(示例):

buildbash
$(CC) scream_demo.c -I. -L. -lscreamdetect -lpthread -lm -o scream_demo
./scream_demo

结语

无论是一间公寓还是一公里街道,目标都一致:让求助的声音不可能被错过。我们提供在线试用与场景化部署支持。