画像処理の積分図は1(半径に関係のない高速ぼかしアルゴリズム)を適用する.


画像処理の積分画像応用一(半径に関係のない高速ぼかしアルゴリズム)
一:基本原理の概要
従来の画像空間領域ボリュームブラーアルゴリズムでは、ウィンドウサイズが変化するとボリュームブラー時間も変化し、ウィンドウサイズが大きいほど計算量も大きくなり、アルゴリズムの実行時間は約長くなる.多くの場合、リアルタイムの要件を満たすことができません.積分画像に基づいてウィンドウ領域とサイズの高速計算を実現することができ、従来のボリュームブラー計算をウィンドウサイズの影響で除去し、ボリュームブラーをウィンドウサイズ半径に関係のない定数時間で完了する操作に変えることができる.画像自体から積分画像を得る方法については、前の記事「画像処理の積分画像アルゴリズム」を参照してください.
二:詳しく説明する
5 x 5のウィンドウサイズを例として、画像I、積分画像II、処理後のぼかし画像BIを仮定すると、従来の空間領域の畳み込みで実現された画像平均ぼかしは、各画素点の式に対して以下のように表される.
積分画像に基づいて各ピクセル点のぼかし式を計算すると、次のようになります.
上記従来の平均ボケ計算によるボケの結果、24回加算と1回除算の計25回の計算を行い、積分画像に基づく1回加算2回減算と1回除算の計4回の計算のみが必要となり、従来の畳み込み平均ボケ計算に基づくウィンドウサイズが大きいほど計算回数が多くなる積分画像に基づいて計算回数は定数を一定に保ち,半径に関係のない平均ぼかしアルゴリズムである.
三:コード実装
積分画像アルゴリズム実装については、以下を参照してください.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の消費時間ヒストグラムは以下の通りである.
他の条件が変更されない場合、ウィンドウの半径が大きいほど、両者の間の実行時間の差が大きくなることがわかります.皆さん、国慶節おめでとうございます.