1. 程式人生 > >影象處理之積分圖應用二(快速邊緣保留濾波演算法)

影象處理之積分圖應用二(快速邊緣保留濾波演算法)

影象處理之積分圖應用二(快速邊緣保留濾波演算法)

一:基本原理

傳統的影象邊緣保留濾波演算法-如高斯雙邊模糊、Mean-Shift模糊等計算複雜、效率比較低,雖然有各種手段優化或者快速計算方法,當時演算法相對一般碼農來說理解起來比較費勁,不是一個的選擇,而通過積分影象實現區域性均方差的邊緣保留模糊演算法,計算簡單而且可以做到計算量跟半徑無關、跟上面提到兩種邊緣保留濾波(EPF)演算法效率高很多。首先區域性均方差濾波中計算區域性均值的公式如下:

當邊緣很弱的時候係數K趨近於0、該點的矯正之後的畫素值就接近平均值。而當邊緣很強的時候係數K趨近於1、該點的模糊之後的畫素值就接近等於輸入畫素值。上述計算中最中意的是視窗內畫素的均值與方差,計算均值可以根據積分影象很容易得到,而計算方差根據一系列的數學推導可以得到如下:



就是說可以根據積分影象通過常量次數的計算得到區域性的均值與方差,讓這種情況下的濾波變成一個常量時間完成的操作與視窗半徑大小無關。

二:演算法流程

1. 根據輸入的影象計算得到積分影象,參見《影象處理之積分影象演算法》

2. 根據輸入的半徑大小計算視窗內畫素均值與方差、計算得到每個畫素新的畫素值

3. 迴圈每個個畫素,重複第2步計算,得到最終的區域性均方差濾波影象

三:程式碼實現


  
  1. package com.gloomyfish.ii.demo;
  2. import java.awt.image.BufferedImage;
  3. /**
  4. * fast edge preserve filter algorithm base on integral image
  5. * @author
    zhigang jia
  6. * @E-mail:[email protected]
  7. *
  8. */
  9. public class FastEPFilter extends AbstractImageOptionFilter {
  10. // 視窗半徑大小
  11. private int xr;
  12. private int yr;
  13. private float sigma;
  14. public FastEPFilter() {
  15. }
  16. public void setWinsize(int radius) {
  17. this.xr = radius;
  18. this.yr = radius;
  19. }
  20. public float getSigma() {
  21. return sigma;
  22. }
  23. public void setSigma(float sigma) {
  24. this.sigma = sigma;
  25. }
  26. @Override
  27. public BufferedImage process(BufferedImage image) {
  28. long time = System.currentTimeMillis();
  29. int width = image.getWidth();
  30. int height = image.getHeight();
  31. // get image data
  32. int[] pixels = new int[width * height];
  33. int[] outPixels = new int[width * height];
  34. getRGB(image, 0, 0, width, height, pixels);
  35. int size = (xr * 2 + 1) * (yr * 2 + 1);
  36. int r = 0, g = 0, b = 0;
  37. float sigma2 = sigma*sigma;
  38. // per-calculate integral image
  39. byte[] R = new byte[width*height];
  40. byte[] G = new byte[width*height];
  41. byte[] B = new byte[width*height];
  42. getRGB(width, height, pixels, R, G, B);
  43. IntIntegralImage rii = new IntIntegralImage();
  44. rii.setImage(R);
  45. rii.process(width, height);
  46. IntIntegralImage gii = new IntIntegralImage();
  47. gii.setImage(G);
  48. gii.process(width, height);
  49. IntIntegralImage bii = new IntIntegralImage();
  50. bii.setImage(B);
  51. bii.process(width, height);
  52. int index = 0;
  53. for ( int row = yr; row < height - yr; row++) {
  54. for ( int col = xr; col < width - xr; col++) {
  55. index = row * width + col;
  56. r = ((pixels[index] >> 16) & 0xff);
  57. g = (pixels[index] >> 8) & 0xff;
  58. b = (pixels[index] & 0xff);
  59. int sr = rii.getBlockSum(col, row, (yr * 2 + 1), (xr * 2 + 1));
  60. int sg = gii.getBlockSum(col, row, (yr * 2 + 1), (xr * 2 + 1));
  61. int sb = bii.getBlockSum(col, row, (yr * 2 + 1), (xr * 2 + 1));
  62. float vr = rii.getBlockSquareSum(col, row, (yr * 2 + 1), (xr * 2 + 1));
  63. float vg = gii.getBlockSquareSum(col, row, (yr * 2 + 1), (xr * 2 + 1));
  64. float vb = bii.getBlockSquareSum(col, row, (yr * 2 + 1), (xr * 2 + 1));
  65. // 計算均值
  66. float mr = sr / size;
  67. float mg = sg / size;
  68. float mb = sb / size;
  69. // 計算方差
  70. float dr = (vr - (sr*sr)/size)/size;
  71. float dg = (vg - (sg*sg)/size)/size;
  72. float db = (vb - (sb*sb)/size)/size;
  73. // 計算係數K
  74. float kr = dr / (dr+sigma2);
  75. float kg = dg / (dg+sigma2);
  76. float kb = db / (db+sigma2);
  77. // 得到濾波後的畫素值
  78. r = ( int)(( 1-kr)*mr + kr*r);
  79. g = ( int)(( 1-kg)*mg + kg*g);
  80. b = ( int)(( 1-kb)*mb + kb*b);
  81. outPixels[row * width + col] = ( 0xff << 24) | (clamp(r) << 16) | (clamp(g) << 8) | clamp(b);
  82. }
  83. }
  84. System.out.println( "FastEPFilter ->> time duration : " + (System.currentTimeMillis() - time));
  85. BufferedImage dest = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
  86. setRGB(dest, 0, 0, width, height, outPixels);
  87. return dest;
  88. }
  89. /** Returns the red, green and blue planes as 3 byte arrays. */
  90. public void getRGB(int width, int height, int[] pixels, byte[] R, byte[] G, byte[] B) {
  91. int c, r, g, b;
  92. for ( int i= 0; i < width*height; i++) {
  93. c = pixels[i];
  94. r = (c& 0xff0000)>> 16;
  95. g = (c& 0xff00)>> 8;
  96. b = c& 0xff;
  97. R[i] = ( byte)r;
  98. G[i] = ( byte)g;
  99. B[i] = ( byte)b;
  100. }
  101. }
  102. }

四:執行效果

半徑設定為5,即視窗大小為5的時候,調整引數sigma的值即可得到此效果

其實很多磨皮的演算法都是基於這個演算法實現的,這個才是我想說的重點,

只有耐心看到此處才可以得到正確的答案。

五:參考:

http://imagej.net/Integral_Image_Filters#Variance

http://www.activovision.com/octavi/doku.php?id=integral_images


轉載自:https://blog.csdn.net/jia20003/article/details/52744157