本文目录导读:

编写一个影音工具来统计“倒三角回敲次数”,这个需求需要先明确几个关键定义,因为“倒三角回敲”在不同场景下含义不同,下面我从概念定义到代码实现给你一套完整方案。
先明确"倒三角回敲"的定义
在影音/音频分析场景中,通常指以下两种之一:
| 场景 | 含义 |
|---|---|
| 音频波形 | 信号出现"先下降、再回升"的 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 元素的闪烁?
- 倒三角:是指波形形状、节奏型,还是某种图形符号?
- 回敲:是物理回弹、节奏反复,还是信号二次触发?
告诉我这几点,我可以把上面的算法改成完全贴合你场景的版本。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播