声音检测
随着人工智能的发展,机器视觉,机器可视化也变的越来越完善,但是声音这块分析资料却比较少,有时候需要去检测一段视频或者音频中是否有声音。在某些场景中需要判断有声音则抓拍录制,当然这里只是先初步检测声音响度,如果还需要更高深的检测比如有人说话,也有其他嘈杂声音,我们如何去区分是人在说话,还是车开过,还是噪音,这个以后再讲。
可用于流媒体视频中实时检测,也可以用于离线文件检测,根据自己的需求,调节soundThreshold阈值,一般情况-65 db 为安静状态。
演示:
话不多说,直接上代码:
package com.zj.example;
import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.UnsupportedAudioFileException;
import com.zj.filter.DetectSoundFilter;
/**
* 识别音频中是否有声音
* @author ZJ
*
*/
public class TestDetectQuiet {
public static void main(String[] args) throws UnsupportedAudioFileException, IOException {
loadFile("./data/安静.wav");
// loadFile("./data/有声.wav");
}
/**
* 读取文件
*/
public static void loadFile(String path) throws UnsupportedAudioFileException, IOException {
File f = new File(path);
AudioInputStream audioStream = AudioSystem.getAudioInputStream(f);
readData(audioStream);
}
/**
* 读取数据
* @throws IOException
*/
public static void readData(AudioInputStream audioStream) throws IOException {
byte[] frame = new byte[2048];
DetectSoundFilter soundFilter = new DetectSoundFilter();
while (true) {
int read = audioStream.read(frame);
if (read < 0) {
break;
}
double[] byteToDouble = byteToDouble(frame);
boolean silence = soundFilter.isSilence(byteToDouble);
if(silence) {
System.out.println("这是安静的");
} else {
System.out.println("这是有声音的");
}
}
}
/**
* pcm转成浮点
* @param data
* @return
*/
public static double[] byteToDouble(byte[] data) {
ByteBuffer buf = ByteBuffer.wrap(data);
buf.order(ByteOrder.BIG_ENDIAN);
int i = 0;
double[] dData = new double[data.length / 2];
while (buf.remaining() > 1) {
short s = buf.getShort();
dData[i] = (double) s / 32767.0; // real
++i;
}
return dData;
}
}
检测声音核心部分:
package com.zj.filter;
/**
* 识别声音过滤器
* 用于判断有没有声音,甚至可以判断声音的响度
*
* @author ZJ
*
*/
public class DetectSoundFilter {
/**
* 声音响度阈值
*/
public double soundThreshold = -60; // db
/**
* 是否安静
* @param buffer
* @param soundThreshold
* @return
*/
public boolean isSilence(final double[] buffer) {
double currentSPL = soundPressureLevel(buffer);
System.out.println(currentSPL);
return currentSPL < soundThreshold;
}
/**
* 声压计算
* @param buffer
* @return
*/
private double soundPressureLevel(final double[] buffer) {
double value = Math.pow(localEnergy(buffer), 0.5);
value = value / buffer.length;
return linearToDecibel(value);
}
/**
* 线性转换为dB值
* @param value
* @return
*/
private double linearToDecibel(final double value) {
return 20.0 * Math.log10(value);
}
/**
* 音频帧去负数
* @param buffer
* @return
*/
private double localEnergy(final double[] buffer) {
double power = 0.0D;
for (double element : buffer) {
power += element * element;
}
return power;
}
}
demo里只是来检测某一帧,实际应用中可能需求不一样,可以自行修改,比如一段时间内都是安静的话,否则不认为是安静。
至此简单的声音响度识别功能实现了。
如果觉得可以,请随手点赞,Thanks♪(・ω・)ノ