SSE圖像算法優化系列十四:局部均方差及局部平方差算法的優化。


  關於局部均方差有着較為廣泛的應用,在我博客的基於局部均方差相關信息的圖像去噪及其在實時磨皮美容算法中的應用使用局部標准差實現圖像的局部對比度增強算法中都有談及,即可以用於去噪也可以用來增強圖像,但是直接計算其計算量較大,一般都是通過某種方式進行優化,典型的即通過積分圖來處理:

          {\text{Var}}(X)={\frac  {1}{n}}\sum _{{i=1}}^{n}(x_{i}-\mu )^{2}\quad {\text{and}}\quad \mu ={\frac  {1}{n}}\sum _{{i=1}}^{n}x_{i}

       展開:

                     {\text{Var}}(x)={\frac  {1}{n}}\sum _{{i=1}}^{n}\left(x_{i}^{2}-2x_{i}\mu +\mu ^{2}\right)

                                  ={\frac  {1}{n}}\sum _{{i=1}}^{n}x_{i}^{2}-{\frac  {1}{n}}\sum _{{i=1}}^{n}2x_{i}\mu +\mu ^{2}

                                  ={\frac  {1}{n}}\sum _{{i=1}}^{n}x_{i}^{2}-{\frac  {1}{n}}\sum _{{i=1}}^{n}2x_{i}\mu +{\frac  {1}{n^{2}}}\left(\sum _{{i=1}}^{n}x_{i}\right)^{2}

                                 ={\frac  {1}{n}}\sum _{{i=1}}^{n}x_{i}^{2}-{\frac  {2\mu }{n}}\sum _{{i=1}}^{n}x_{i}+{\frac  {1}{n^{2}}}\left(\sum _{{i=1}}^{n}x_{i}\right)^{2}

                                 ={\frac  {1}{n}}\sum _{{i=1}}^{n}x_{i}^{2}-{\frac  {2}{n^{2}}}\left(\sum _{{i=1}}^{n}x_{i}\right)^{2}+{\frac  {1}{n^{2}}}\left(\sum _{{i=1}}^{n}x_{i}\right)^{2}

                                 ={\frac  {1}{n}}\sum _{{i=1}}^{n}x_{i}^{2}-{\frac  {1}{n^{2}}}\left(\sum _{{i=1}}^{n}x_{i}\right)^{2}

                                 ={\frac  {1}{n}}\sum _{{i=1}}^{n}x_{i}^{2}-\left({\frac  {1}{n}}\sum _{{i=1}}^{n}x_{i}\right)^{2}

                                ={\frac  {1}{n}}\left(\sum _{{i=1}}^{n}x_{i}^{2}-{\frac  {1}{n}}\left(\sum _{{i=1}}^{n}x_{i}\right)^{2}\right)

  上式中兩個累積一個是平方積分圖,一個是累加積分圖,累加積分圖在SSE圖像算法優化系列六:OpenCv關於灰度積分圖的SSE代碼學習和改進中曾經談及,而平方積分圖由於數據范圍的問題,用int類型的數據來處理的話,只能處理很小很小的圖,因此需要使用浮點類型,經過測試,如果使用SSE指令,由於SSE的浮點計算精度實在是低,比FPU的還要低,積分圖這種累加性質的算法計算出來的結果會存在很大的誤差,特別是在圖像比較寬而半徑比較小時,會看到明顯的錯誤結果,半徑稍微大點時,也會有明顯豎條紋出現(小圖像好像不會出現什么大問題),如下圖所示:

                 

            小半徑                          大半徑                     合理的結果     

  因此,如果使用積分圖,考慮各種類型的圖像,最好是使用double類型保存中間的積分圖數據,這是個很可觀的內存消耗,也會導致時間的增加。

  在SSE圖像算法優化系列十三:超高速BoxBlur算法的實現和優化(Opencv的速度的五倍)一文中,我們描述了Boxblur的優化,優化后的速度即比傳統的快,也占用很少的內存,我們觀察下BoxBlur的累加式: 以及像素平方的累加式,他們除理數據不一樣外,其他並無本質的區別的,因此也是可以使用類似於Boxblur的方式進行優化和處理的,這樣上述算法就變為了2個這種累積算法的同步進行算法,並且同步進行能夠減少很多重復數據的加載和處理,比單獨進行兩個過程其實是要更節省時間的。

  那么需要注意的時,由於是對像素的平方進行累加,還考慮使用int類型來保存列累加值以及水平方向的累加值,那么理論上講最大的安全半徑可以達到90(不會產生溢出),計算如下:

    Sqrt(Int.MaxValue / (Byte.MaxValue * Byte.MaxValue)) / 2 - 1 = Sqrt(2147483647 / 65025) / 2 - 1 = 90

  對於局部均方差相關的算法來說,90的半徑已經完全滿足了實際的需求。

  使用SSE優化,實際測試表面,對於3000*2000的灰度圖求取均方差大約需要13ms(包括了最后的求sqrt過程的時間,是相當快的)。

  另外,局部均方差是像素領域的值減去該領域的平均值的平方累積和,這樣的結果在強邊緣處均方差會特別強烈,用於某法會出現邊緣效應,如果我們對這個稍微改造下,使用像素領域的值減去領域的模糊值,在求累加值,會不會有什么結果呢,此時假如平均值用y表示,則需要計算這個值,同樣的y就是上述的Boxblur的值,計算這個的優化方式和Boxblur又是相同的,一環套一環,當然這個時候的速度會比上面的慢一點,因此公共的計算不能重復利用了,大概需要17ms。

  更廣泛的講,還可以用上述方式計算任意兩幅圖像的局部平方差,速度和效率同樣很高。比如計算原圖和高斯模糊后的圖的局部平法差,會得到什么結果呢?

  使用這種方式優化后,我以前提的磨皮算法針對1080P的圖可以做到約20ms每幀,而且效果非常好,完全可以使用到視頻處理中。

  參考效果下載:https://files.cnblogs.com/files/Imageshop/SSE_Optimization_Demo.rar,見其中的Boxblur - >LeeAddtiveNoiseFilter 以及Enhance ->MakeUp和ImageInfo->Stdfilter等。

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM