關於局部均方差有着較爲普遍的應用,在我博客的基於局部均方差相關信息的圖像去噪及其在實時磨皮美容算法中的應用及使用局部標準差實現圖像的局部對比度加強算法中都有談及,便可以用於去噪也能夠用來加強圖像,可是直接計算其計算量較大,通常都是經過某種方式進行優化,典型的即經過積分圖來處理:html
展開:算法
上式中兩個累積一個是平方積分圖,一個是累加積分圖,累加積分圖在SSE圖像算法優化系列六:OpenCv關於灰度積分圖的SSE代碼學習和改進中曾經談及,而平方積分圖因爲數據範圍的問題,用int類型的數據來處理的話,只能處理很小很小的圖,所以須要使用浮點類型,通過測試,若是使用SSE指令,因爲SSE的浮點計算精度實在是低,比FPU的還要低,積分圖這種累加性質的算法計算出來的結果會存在很大的偏差,特別是在圖像比較寬而半徑比較小時,會看到明顯的錯誤結果,半徑稍微大點時,也會有明顯豎條紋出現(小圖像好像不會出現什麼大問題),以下圖所示:安全
小半徑 大半徑 合理的結果 post
所以,若是使用積分圖,考慮各類類型的圖像,最好是使用double類型保存中間的積分圖數據,這是個很可觀的內存消耗,也會致使時間的增長。學習
在SSE圖像算法優化系列十三:超高速BoxBlur算法的實現和優化(Opencv的速度的五倍)一文中,咱們描述了Boxblur的優化,優化後的速度即比傳統的快,也佔用不多的內存,咱們觀察下BoxBlur的累加式: 以及像素平方的累加式,他們除理數據不同外,其餘並沒有本質的區別的,所以也是可使用相似於Boxblur的方式進行優化和處理的,這樣上述算法就變爲了2個這種累積算法的同步進行算法,而且同步進行可以減小不少重複數據的加載和處理,比單獨進行兩個過程實際上是要更節省時間的。測試
那麼須要注意的時,因爲是對像素的平方進行累加,還考慮使用int類型來保存列累加值以及水平方向的累加值,那麼理論上講最大的安全半徑能夠達到90(不會產生溢出),計算以下:優化
Sqrt(Int.MaxValue / (Byte.MaxValue * Byte.MaxValue)) / 2 - 1 = Sqrt(2147483647 / 65025) / 2 - 1 = 90url
對於局部均方差相關的算法來講,90的半徑已經徹底知足了實際的需求。spa
使用SSE優化,實際測試表面,對於3000*2000的灰度圖求取均方差大約須要13ms(包括了最後的求sqrt過程的時間,是至關快的)。
3d
另外,局部均方差是像素領域的值減去該領域的平均值的平方累積和,這樣的結果在強邊緣處均方差會特別強烈,用於某法會出現邊緣效應,若是咱們對這個稍微改造下,使用像素領域的值減去領域的模糊值,在求累加值,會不會有什麼結果呢,此時假如平均值用y表示,則須要計算這個值,一樣的y就是上述的Boxblur的值,計算這個的優化方式和Boxblur又是相同的,一環套一環,固然這個時候的速度會比上面的慢一點,所以公共的計算不能重複利用了,大概須要17ms。
更普遍的講,還能夠用上述方式計算任意兩幅圖像的局部平方差,速度和效率一樣很高。好比計算原圖和高斯模糊後的圖的局部平法差,會獲得什麼結果呢?
使用這種方式優化後,我之前提的磨皮算法針對1080P的圖能夠作到約20ms每幀,並且效果很是好,徹底可使用到視頻處理中。
參考效果下載:https://files.cnblogs.com/files/Imageshop/SSE_Optimization_Demo.rar,見其中的Boxblur - >LeeAddtiveNoiseFilter 以及Enhance ->MakeUp和ImageInfo->Stdfilter等。