本文目录导读:

编写一个影音工具来统计“倒三角回敲次数”,这个需求需要先明确几个关键定义,因为“倒三角回敲”在不同场景下含义不同,下面我从概念定义到代码实现给你一套完整方案。
先明确"倒三角回敲"的定义
在影音/音频分析场景中,通常指以下两种之一:
| 场景 | 含义 |
|---|---|
| 音频波形 | 信号出现"先下降、再回升"的 V 型/倒三角形态 |
| 鼓点/敲击 | 一段连续衰减后突然回弹的敲击事件(如鼓棒回敲) |
| 视频帧 | 画面亮度/运动量呈倒三角波动的次数 |
下面以音频敲击回敲检测为例(最常见),给出可运行的方案。
核心算法思路
读取音频 → 单声道 → 采样率 sr
2. 计算能量包络(短时能量 / RMS)
3. 检测"敲击起始点"(onset)
4. 在每个敲击事件内,判断是否出现:
能量下降 → 局部极小 → 能量回升 (倒三角形态)
5. 满足则计数 +1
Python 实现(基于 librosa)
import librosa
import numpy as np
import scipy.signal as signal
def count_inverted_triangle_knocks(audio_path,
hop_length=512,
frame_length=2048,
drop_ratio=0.6, # 下降幅度阈值
rise_ratio=0.4, # 回升幅度阈值
min_gap=0.15): # 两次回敲最小间隔(秒)
"""
统计音频中"倒三角回敲"次数
"""
# 1. 读取音频
y, sr = librosa.load(audio_path, sr=None, mono=True)
# 2. 计算 RMS 能量包络
rms = librosa.feature.rms(y=y,
frame_length=frame_length,
hop_length=hop_length)[0]
rms = rms / (np.max(rms) + 1e-9) # 归一化
# 3. 检测敲击起始点
onset_frames = librosa.onset.onset_detect(
y=y, sr=sr, hop_length=hop_length, backtrack=True
)
onset_times = librosa.frames_to_time(onset_frames, sr=sr,
hop_length=hop_length)
# 4. 逐个敲击事件分析
count = 0
events = []
last_time = -999
for i, t in enumerate(onset_times):
# 事件窗口:当前 onset 到下一个 onset
start = onset_frames[i]
end = onset_frames[i+1] if i+1 < len(onset_frames) else len(rms)
seg = rms[start:end]
if len(seg) < 5:
continue
# 找峰值位置
peak_idx = int(np.argmax(seg))
peak_val = seg[peak_idx]
# 峰值之后是否有明显下降再回升
after = seg[peak_idx:]
if len(after) < 4:
continue
trough_idx = int(np.argmin(after))
trough_val = after[trough_idx]
# 峰值后是否至少下降 drop_ratio
if peak_val - trough_val < drop_ratio * peak_val:
continue
# 谷底之后是否回升 rise_ratio
after_trough = after[trough_idx:]
if len(after_trough) < 3:
continue
rebound_val = np.max(after_trough)
if rebound_val - trough_val < rise_ratio * peak_val:
continue
# 最小间隔去重
if t - last_time < min_gap:
continue
count += 1
last_time = t
events.append({
"time": round(t, 3),
"peak": round(float(peak_val), 3),
"trough": round(float(trough_val), 3),
"rebound": round(float(rebound_val), 3),
})
return count, events
if __name__ == "__main__":
n, ev = count_inverted_triangle_knocks("test.wav")
print(f"倒三角回敲次数: {n}")
for e in ev:
print(e)
参数调优建议
| 参数 | 作用 | 建议值 |
|---|---|---|
drop_ratio |
峰值→谷底下降幅度 | 4 ~ 0.7 |
rise_ratio |
谷底→回升幅度 | 3 ~ 0.6 |
min_gap |
去重最小间隔 | 1 ~ 0.3 秒 |
frame_length |
包络平滑度 | 1024 ~ 4096 |
可视化辅助(可选)
import matplotlib.pyplot as plt
def plot_events(audio_path, events):
y, sr = librosa.load(audio_path, sr=None, mono=True)
t = np.arange(len(y)) / sr
plt.figure(figsize=(12, 3))
plt.plot(t, y, lw=0.5, alpha=0.6)
for e in events:
plt.axvline(e["time"], color='r', ls='--', alpha=0.7)
plt.title(f"Detected inverted-triangle knocks: {len(events)}")
plt.tight_layout()
plt.show()
如果你指的是别的场景
请补充一下你的具体需求,我可以针对性修改:
- 音频:是鼓点、脚步、键盘敲击,还是某种乐器?
- 视频:是画面运动、亮度变化,还是特定 UI 元素的闪烁?
- 倒三角:是指波形形状、节奏型,还是某种图形符号?
- 回敲:是物理回弹、节奏反复,还是信号二次触发?
告诉我这几点,我可以把上面的算法改成完全贴合你场景的版本。
版权声明:除非特别标注,否则均为本站原创文章,转载时请以链接形式注明文章出处。