影象處理之積分圖應用一(半徑無關的快速模糊演算法)
阿新 • • 發佈:2018-11-11
影象處理之積分影象應用一(半徑無關的快速模糊演算法)
一:基本原理概述
傳統的影象空間域卷積模糊演算法,當視窗大小改變時卷積模糊時間也會變化,而且隨著視窗尺寸越大計算量也越大,演算法執行時間約越長。在很多時候無法滿足實時性要求。而基於積分影象可以實現對視窗區域和大小的快速計算,把傳統卷積模糊計算受視窗大小影響消除,把卷積模糊變成一個與視窗大小半徑無關的常量時間完成的操作。關於如何從影象本身得到積分影象的演算法請看上一篇文章《影象處理之積分影象演算法》
二:詳細解釋
以5x5的視窗大小為例,假設影象I、積分影象II、處理之後模糊影象BI、則傳統空間域卷積實現的影象均值模糊對每個畫素點公式表示如下:
基於積分影象計算每個畫素點模糊公式表示如下:
上述基於傳統的均值模糊計算得到模糊之後的結果要計算24次加法和一次除法共計25次計算,而基於積分影象則只需要一次加法兩次減法和一次除法共計四次計算,而且基於傳統卷積均值模糊計算當視窗大小越大計算次數也越多,而基於積分影象則計算次數保持常量不變,是一個半徑無關的均值模糊演算法。
三:程式碼實現
積分影象演算法實現參見:http://blog.csdn.net/jia20003/article/details/52710751
傳統模式的卷積模糊程式碼如下:
-
package
com.gloomyfish.ii.demo;
-
-
import java.awt.image.BufferedImage;
-
-
public
class Convolution2DFilter extends AbstractImageOptionFilter
{
-
// 視窗半徑大小
-
private
int xr;
-
private
int yr;
-
-
public Convolution2DFilter() {
-
xr =
1;
-
yr =
1;
-
}
-
-
public int getXr() {
-
return xr;
-
}
-
-
public void setXr(int xr) {
-
this.xr = xr;
-
}
-
-
public int getYr() {
-
return yr;
-
}
-
-
public void setYr(int yr) {
-
this.yr = yr;
-
}
-
-
@Override
-
public BufferedImage process(BufferedImage image) {
-
long time = System.currentTimeMillis();
-
int width = image.getWidth();
-
int height = image.getHeight();
-
-
int[] pixels =
new
int[width * height];
-
int[] outPixels =
new
int[width * height];
-
getRGB(image,
0,
0, width, height, pixels);
-
int size = (xr *
2 +
1) * (yr *
2 +
1);
-
int r =
0, g =
0, b =
0;
-
-
for (
int row = yr; row < height - yr; row++) {
-
for (
int col = xr; col < width - xr; col++) {
-
int sr =
0, sg =
0, sb =
0;
-
// 鍗風Н錼嶄綔/妯℃澘璁$畻
-
for (
int i = -yr; i <= yr; i++) {
-
int roffset = row + i;
-
for (
int j = -xr; j <= xr; j++) {
-
int coffset = col + j;
-
sr += ((pixels[roffset * width + coffset] >>
16) &
0xff);
-
sg += (pixels[roffset * width + coffset] >>
8) &
0xff;
-
sb += (pixels[roffset * width + coffset] &
0xff);
-
}
-
}
-
-
r = sr / size;
-
g = sg / size;
-
b = sb / size;
-
outPixels[row * width + col] = (
0xff <<
24) | (r <<
16) | (g <<
8) | b;
-
}
-
}
-
System.out.println(
"Convolution2DFilter ->> time duration : " + (System.currentTimeMillis() - time));
-
BufferedImage dest =
new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
-
setRGB(dest,
0,
0, width, height, outPixels);
-
return dest;
-
}
-
-
}
基於積分影象的快速模糊程式碼如下:
-
package com.gloomyfish.ii.demo;
-
-
import java.awt.image.BufferedImage;
-
-
public
class FastBlurFilter extends AbstractImageOptionFilter {
-
// 視窗半徑大小
-
private
int xr;
-
private
int yr;
-
-
public FastBlurFilter() {
-
xr =
1;
-
yr =
1;
-
}
-
-
public int getXr() {
-
return xr;
-
}
-
-
public void setXr(int xr) {
-
this.xr = xr;
-
}
-
-
public int getYr() {
-
return yr;
-
}
-
-
public void setYr(int yr) {
-
this.yr = yr;
-
}
-
-
@Override
-
public BufferedImage process(BufferedImage image) {
-
long time = System.currentTimeMillis();
-
int width = image.getWidth();
-
int height = image.getHeight();
-
// get image data
-
int[] pixels =
new
int[width * height];
-
int[] outPixels =
new
int[width * height];
-
getRGB(image,
0,
0, width, height, pixels);
-
int size = (xr *
2 +
1) * (yr *
2 +
1);
-
int r =
0, g =
0, b =
0;
-
-
// per-calculate integral image
-
byte[] R =
new
byte[width*height];
-
byte[] G =
new
byte[width*height];
-
byte[] B =
new
byte[width*height];
-
getRGB(width, height, pixels, R, G, B);
-
IntIntegralImage rii =
new IntIntegralImage();
-
rii.setImage(R);
-
rii.process(width, height);
-
IntIntegralImage gii =
new IntIntegralImage();
-
gii.setImage(G);
-
gii.process(width, height);
-
IntIntegralImage bii =
new IntIntegralImage();
-
bii.setImage(B);
-
bii.process(width, height);
-
-
for (
int row = yr; row < height - yr; row++) {
-
for (
int col = xr; col < width - xr; col++) {
-
int sr = rii.getBlockSum(col, row, (yr *
2 +
1), (xr *
2 +
1));
-
int sg = gii.getBlockSum(col, row, (yr *
2 +
1), (xr *
2 +
1));
-
int sb = bii.getBlockSum(col, row, (yr *
2 +
1), (xr *
2 +
1));
-
r = sr / size;
-
g = sg / size;
-
b = sb / size;
-
outPixels[row * width + col] = (
0xff <<
24) | (r <<
16) | (g <<
8) | b;
-
}
-
}
-
System.out.println(
"FastBlurFilter ->> time duration : " + (System.currentTimeMillis() - time));
-
BufferedImage dest =
new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
-
setRGB(dest,
0,
0, width, height, outPixels);
-
return dest;
-
}
-
-
/** Returns the red, green and blue planes as 3 byte arrays. */
-
public void getRGB(int width, int height, int[] pixels, byte[] R, byte[] G, byte[] B) {
-
int c, r, g, b;
-
for (
int i=
0; i < width*height; i++) {
-
c = pixels[i];
-
r = (c&
0xff0000)>>
16;
-
g = (c&
0xff00)>>
8;
-
b = c&
0xff;
-
R[i] = (
byte)r;
-
G[i] = (
byte)g;
-
B[i] = (
byte)b;
-
}
-
}
-
-
}
四:效率之比
分別把視窗半徑調整到1、3、10、20的情況下,對同一張影象做模糊處理,CPU耗時直方圖如下:
可見在其它條件不改變的情況下,視窗半徑越大,兩者之間執行時間差距越大。各位國慶節快樂!