图像处理之积分图应用一(半径无关的快速模糊算法)

图像处理之积分图像应用一(半径无关的快速模糊算法)

一:基本原理概述

传统的图像空间域卷积模糊算法,当窗口大小改变时卷积模糊时间也会变化,而且随着窗口尺寸越大计算量也越大,算法运行时间约越长。在很多时候无法满足实时性要求。而基于积分图像可以实现对窗口区域和大小的快速计算,把传统卷积模糊计算受窗口大小影响消除,把卷积模糊变成一个与窗口大小半径无关的常量时间完成的操作。关于如何从图像本身得到积分图像的算法请看上一篇文章《图像处理之积分图像算法》

二:详细解释

以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耗时直方图如下:


可见在其它条件不改变的情况下,窗口半径越大,两者之间执行时间差距越大。各位国庆节快乐!

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

gloomyfish

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值