轉自:http://www.cnblogs.com/cpuimage/p/8846951.html
人們所熟知的圖像方面的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/ReplayGain
現在大多數的音頻播放器都支持這個特性。
根據維基上的說明,現在大多數使用的開源實現是 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://cpuimage.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
得到對應的評估結果之后,接下來作何處理,就看各位看官的具體需求了。
若有其他相關問題或者需求也可以郵件聯系俺探討。
郵箱地址是:
gaozhihan@vip.qq.com