人们所熟知的图像方面的 3A 算法有:
AF 自动对焦 (Automatic Focus)
自动对焦即调节摄像头焦距自动得到清晰的图像的过程
AE 自动曝光 (Automatic Exposure)
自动曝光的是为了使感光器件获得合适的曝光量
AW 自动白平衡 (Automatic White Balance)
白平衡的本质是使白色物体在任何光源下都显示白色
与之相对应的音频方面的 3A 算法是:
AGC 自动增益补偿 (Automatic Gain Control)
自动调麦克风的收音量, 使与会者收到一定的音量水平, 不会因发言者与麦克风的距离改变时, 声音有忽大忽小声的缺点.
ANS 背景噪音抑制 (Automatic Noise Suppression)
探测出背景固定频率的杂音并消除背景噪音.
AEC 是回声消除器 (Acoustic Echo Canceller)
对扬声器信号与由它产生的多路径回声的相关性为基础, 建立远端信号的语音模型, 利用它对回声进行估计, 并不断地修改滤波器的系数, 使得估计值更加逼近真实的回声. 然后, 将回声估计值从话筒的输入信号中减去, 从而达到消除回声的目的, AEC 还将话筒的输入与扬声器过去的值相比较, 从而消除延长延迟的多次反射的声学回声. 根椐存储器存放的过去的扬声器的输出值的多少, AEC 可以消除各种延迟的回声.
图像方面的算法就不多说了, 图像方面的 3a 算法, 本人都实现了.
自动白平衡的主要思路, 就是如何判断图像是否偏色, 偏色后如何修复的问题.
常见的有直方图均衡, 自动对比度, 自动色阶等等.
自动曝光也是要做曝光评估, 常见的有 gama 调节等等.
后续有时间, 再陆续贴出相应的代码.
在这里, 先卖个关子, 占个坑.
而在音频算法方面, 自动增益补偿的算法有点类似图像的自动曝光算法.
主要要考虑的是多长的音频, 怎么分析当前音频的音量或者强度.
根据这个强度对整个音频做一个归一化拉伸, 诸如此类.
图像与音频殊途同归.
而历史悠久的算法, 莫过于, ReplayGain
ReplayGain
是 David Robinson 在 2001 年发布的一项建议标准, 用于衡量计算机音频格式 https://en.wikipedia.org/wiki/Audio_format 中音频的
响度 https://en.wikipedia.org/wiki/Loudness .
相关的维基资料:
https://en.wikipedia.org/wiki/ReplayGain
现在大多数的音频播放器都支持这个特性.
根据维基上的说明, 现在大多数使用的开源实现是 https://en.wikipedia.org/wiki/MP3Gain
资料见:
http://wiki.hydrogenaud.io/index.php?title=Replaygain#Players_support
开源项目地址:
http://mp3gain.sourceforge.net/
项目是 C 代码, 非常干净.
主要的算法实现文件见: gain_analysis.h 与 gain_analysis.c
算法是根据传入的音频数据, 分析需要进行增益的分贝值.
不需要增益则为 0, 需要增益则为对应的浮点正数或负数.
当然, 不能传入太少的音频样本, 否则无法客观分析.
算法只需要传入音频的数据和指定需要分析的样本长度即可.
最终输出一个 推荐增益的分贝值.
根据这个分贝值进行换算, 即可以对目标音频做一些特定的音频处理.
贴上完整的 C 代码:
- #ifdef __cplusplus
- extern "C" {
- #endif
- #include <stdio.h>
- #include <stdlib.h>
- #include <stdint.h>
- // 采用 https://github.com/mackron/dr_libs/blob/master/dr_wav.h 解码
- #define DR_WAV_IMPLEMENTATION
- #include "dr_wav.h"
- #include "gain_analysis.h"
- #ifndef min
- #define min(a, b) (((a) <(b)) ? (a) : (b))
- #endif
- // 读取 wav 文件
- int16_t *wavRead_int16(char *filename, uint32_t *sampleRate, uint64_t *totalSampleCount) {
- unsigned int channels;
- int16_t *buffer = drwav_open_and_read_file_s16(filename, &channels, sampleRate, totalSampleCount);
- if (buffer == NULL) {
- printf("读取 wav 文件失败.");
- }
- // 仅仅处理单通道音频
- if (channels != 1) {
- drwav_free(buffer);
- buffer = NULL;
- *sampleRate = 0;
- *totalSampleCount = 0;
- }
- return buffer;
- }
- float getGaindB(int16_t *buffer, size_t totalSampleCount, int sampleRate, size_t analyzeSamples) {
- float ret = -0.00000000001f;
- if (totalSampleCount == 0) return ret;
- if (analyzeSamples == 0) return ret;
- const int maxSamples = 2400;
- analyzeSamples = min(maxSamples, analyzeSamples);
- ret = 1.0f;
- int num_channels = 1;
- Float_t inf_buffer[maxSamples];
- size_t totalCount = totalSampleCount / analyzeSamples;
- if (InitGainAnalysis(sampleRate) == INIT_GAIN_ANALYSIS_OK) {
- int16_t *input = buffer;
- for (int i = 0; i < totalCount; i++) {
- for (int n = 0; n < analyzeSamples; n++) {
- inf_buffer[n] = input[n];
- }
- if (AnalyzeSamples(inf_buffer, NULL, analyzeSamples, num_channels) != GAIN_ANALYSIS_OK)
- break;
- GetTitleGain();
- // printf("Recommended dB change for analyzeSamples %d: % 6.2f dB\n", i, titleGain);
- input += analyzeSamples;
- }
- ret = GetAlbumGain();
- }
- if ((int) ret == GAIN_NOT_ENOUGH_SAMPLES) {
- ret = -0.00000000001f;
- }
- return ret;
- }
- void analyze(char *in_file, int ref_ms) {
- uint32_t sampleRate = 0;
- uint64_t totalSampleCount = 0;
- int16_t *wavBuffer = wavRead_int16(in_file, &sampleRate, &totalSampleCount);
- if (wavBuffer != NULL) {
- size_t analyzeSamples = ref_ms * (sampleRate / 1000);
- float gain = getGaindB(wavBuffer, totalSampleCount, sampleRate, analyzeSamples);
- printf("recommended dB change: %f \n", gain);
- free(wavBuffer);
- }
- }
- int main(int argc, char *argv[]) {
- printf("Replay Gain Analysis\n");
- printf("blog:http://tntmonks.cnblogs.com/\n");
- printf("e-mail:gaozhihan@vip.qq.com\n");
- if (argc < 2)
- return -1;
- char *in_file = argv[1];
- // 指定分析长度 1 秒
- int ref_ms = 1000;
- analyze(in_file, ref_ms);
- getchar();
- printf("press any key to exit. \n");
- return 0;
- }
- #ifdef __cplusplus
- }
- #endif
我的习惯, 尽量少些注释, 代码尽量干净整洁.
所以大家直接看代码吧.
项目地址: https://github.com/cpuimage/ReplayGainAnalysis
示例具体流程为:
加载 wav(拖放 wav 文件到可执行文件上)-> 输出结果 -> 保存 wav
得到对应的评估结果之后, 接下来作何处理, 就看各位看官的具体需求了.
来源: https://www.cnblogs.com/tntmonks/p/8846951.html