Java编程实现高斯模糊和图像的空间卷积详解

高斯模糊

高斯模糊(英语:Gaussian Blur),也叫高斯平滑,是在Adobe Photoshop、GIMP以及Paint.NET等图像处理软件中广泛使用的处理效果,通常用它来减少图像杂讯以及降低细节层次。这种模糊技术生成的图像,其视觉效果就像是经过一个半透明屏幕在观察图像,这与镜头焦外成像效果散景以及普通照明阴影中的效果都明显不同。高斯平滑也用于计算机视觉算法中的预先处理阶段,以增强图像在不同比例大小下的图像效果。 从数学的角度来看,图像的高斯模糊过程就是图像与正态分布做卷积。由于正态分布又叫作高斯分布,所以这项技术就叫作高斯模糊。图像与圆形方框模糊做卷积将会生成更加精确的焦外成像效果。由于高斯函数的傅立叶变换是另外一个高斯函数,所以高斯模糊对于图像来说就是一个低通滤波器。

高斯模糊运用了高斯的正态分布的密度函数,计算图像中每个像素的变换。

根据一维高斯函数,可以推导得到二维高斯函数:

其中r是模糊半径,r^2 = x^2 + y^2,σ是正态分布的标准偏差。在二维空间中,这个公式生成的曲面的等高线是从中心开始呈正态分布的同心圆。分布不为零的像素组成的卷积矩阵与原始图像做变换。每个像素的值都是周围相邻像素值的加权平均。原始像素的值有最大的高斯分布值,所以有最大的权重,相邻像素随着距离原始像素越来越远,其权重也越来越小。这样进行模糊处理比其它的均衡模糊滤波器更高地保留了边缘效果。

其实,在iOS上实现高斯模糊是件很容易的事儿。早在iOS 5.0就有了Core Image的API,而且在CoreImage.framework库中,提供了大量的滤镜实现。

+(UIImage *)coreBlurImage:(UIImage *)image withBlurNumber:(CGFloat)blur
{
  CIContext *context = [CIContext contextWithOptions:nil];
  CIImage *inputImage= [CIImage imageWithCGImage:image.CGImage];
  //设置filter
  CIFilter *filter = [CIFilter filterWithName:@"CIGaussianBlur"];
  [filter setValue:inputImage forKey:kCIInputImageKey]; [filter setValue:@(blur) forKey: @"inputRadius"];
  //模糊图片
  CIImage *result=[filter valueForKey:kCIOutputImageKey];
  CGImageRef outImage=[context createCGImage:result fromRect:[result extent]];
  UIImage *blurImage=[UIImage imageWithCGImage:outImage];
  CGImageRelease(outImage);
  return blurImage;
}

在Android上实现高斯模糊也可以使用原生的API—–RenderScript,不过需要Android的API是17以上,也就是Android 4.2版本。

/**
   * 使用RenderScript实现高斯模糊的算法
   * @param bitmap
   * @return
   */
public Bitmap blur(Bitmap bitmap){
	//Let's create an empty bitmap with the same size of the bitmap we want to blur
	Bitmap outBitmap = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888);
	//Instantiate a new Renderscript
	RenderScript rs = RenderScript.create(getApplicationContext());
	//Create an Intrinsic Blur Script using the Renderscript
	ScriptIntrinsicBlur blurScript = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));
	//Create the Allocations (in/out) with the Renderscript and the in/out bitmaps
	Allocation allIn = Allocation.createFromBitmap(rs, bitmap);
	Allocation allOut = Allocation.createFromBitmap(rs, outBitmap);
	//Set the radius of the blur: 0 < radius <= 25
	blurScript.setRadius(20.0f);
	//Perform the Renderscript
	blurScript.setInput(allIn);
	blurScript.forEach(allOut);
	//Copy the final bitmap created by the out Allocation to the outBitmap
	allOut.copyTo(outBitmap);
	//recycle the original bitmap
	bitmap.recycle();
	//After finishing everything, we destroy the Renderscript.
	rs.destroy();
	return outBitmap;
}

我们开发的图像框架cv4j也提供了一个滤镜来实现高斯模糊。

GaussianBlurFilter filter = new GaussianBlurFilter();
filter.setSigma(10);

RxImageData.bitmap(bitmap).addFilter(filter).into(image2);

可以看出,cv4j实现的高斯模糊跟RenderScript实现的效果一致。

其中,GaussianBlurFilter的代码如下:

public class GaussianBlurFilter implements CommonFilter {
	private float[] kernel;
	private double sigma = 2;
	ExecutorService mExecutor;
	CompletionService<Void> service;
	public GaussianBlurFilter() {
		kernel = new float[0];
	}
	public void setSigma(double a) {
		this.sigma = a;
	}
	@Override
	  public ImageProcessor filter(final ImageProcessor src){
		final int width = src.getWidth();
		final int height = src.getHeight();
		final int size = width*height;
		int dims = src.getChannels();
		makeGaussianKernel(sigma, 0.002, (int)Math.min(width, height));
		mExecutor = TaskUtils.newFixedThreadPool("cv4j",dims);
		service = new ExecutorCompletionService<>(mExecutor);
		// save result
		for (int i=0; i<dims; i++) {
			final int temp = i;
			service.submit(new Callable<Void>() {
				public Void call() throws Exception {
					byte[] inPixels = src.tobyte(temp);
					byte[] temp = new byte[size];
					blur(inPixels, temp, width, height);
					// H Gaussian
					blur(temp, inPixels, height, width);
					// V Gaussain
					return null;
				}
			}
			);
		}
		for (int i = 0; i < dims; i++) {
			try {
				service.take();
			}
			catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		mExecutor.shutdown();
		return src;
	}
	/**
   * <p> here is 1D Gaussian    , </p>
   *
   * @param inPixels
   * @param outPixels
   * @param width
   * @param height
   */
	private void blur(byte[] inPixels, byte[] outPixels, int width, int height)
	  {
		int subCol = 0;
		int index = 0, index2 = 0;
		float sum = 0;
		int k = kernel.length-1;
		for (int row=0; row<height; row++) {
			int c = 0;
			index = row;
			for (int col=0; col<width; col++) {
				sum = 0;
				for (int m = -k; m< kernel.length; m++) {
					subCol = col + m;
					if(subCol < 0 || subCol >= width) {
						subCol = 0;
					}
					index2 = row * width + subCol;
					c = inPixels[index2] & 0xff;
					sum += c * kernel[Math.abs(m)];
				}
				outPixels[index] = (byte)Tools.clamp(sum);
				index += height;
			}
		}
	}
	public void makeGaussianKernel(final double sigma, final double accuracy, int maxRadius) {
		int kRadius = (int)Math.ceil(sigma*Math.sqrt(-2*Math.log(accuracy)))+1;
		if (maxRadius < 50) maxRadius = 50;
		// too small maxRadius would result in inaccurate sum.
		if (kRadius > maxRadius) kRadius = maxRadius;
		kernel = new float[kRadius];
		for (int i=0; i<kRadius; i++)        // Gaussian function
		kernel[i] = (float)(Math.exp(-0.5*i*i/sigma/sigma));
		double sum;
		// sum over all kernel elements for normalization
		if (kRadius < maxRadius) {
			sum = kernel[0];
			for (int i=1; i<kRadius; i++)
			        sum += 2*kernel[i];
		} else
		      sum = sigma * Math.sqrt(2*Math.PI);
		for (int i=0; i<kRadius; i++) {
			double v = (kernel[i]/sum);
			kernel[i] = (float)v;
		}
		return;
	}
}

空间卷积

二维卷积在图像处理中会经常遇到,图像处理中用到的大多是二维卷积的离散形式。

以下是cv4j实现的各种卷积效果。

cv4j 目前支持如下的空间卷积滤镜

filter 名称 作用
ConvolutionHVFilter 卷积 模糊或者降噪
MinMaxFilter 最大最小值滤波 去噪声
SAPNoiseFilter 椒盐噪声 增加噪声
SharpFilter 锐化 增强
MedimaFilter 中值滤波 去噪声
LaplasFilter 拉普拉斯 提取边缘
FindEdgeFilter 寻找边缘 梯度提取
SobelFilter 梯度 获取x、y方向的梯度提取
VarianceFilter 方差滤波 高通滤波
MaerOperatorFilter 马尔操作 高通滤波
USMFilter USM 增强

cv4j 是gloomyfish和我一起开发的图像处理库,目前还处于早期的版本。

目前已经实现的功能:

这周,我们对 cv4j 做了较大的调整,对整体架构进行了优化。还加上了空间卷积功能(图片增强、锐化、模糊等等)。接下来,我们会做二值图像的分析(腐蚀、膨胀、开闭操作、轮廓提取等等)

总结

以上就是本文关于Java编程实现高斯模糊和图像的空间卷积详解的全部内容,希望对大家有所帮助。感兴趣的朋友可以继续参阅本站:

70行Java代码实现深度神经网络算法分享

Java语言基于无向有权图实现克鲁斯卡尔算法代码示例

java算法实现红黑树完整代码示例

如有不足之处,欢迎留言指出。感谢朋友们对本站的支持!

时间: 2017-11-22

Java常用HASH算法总结【经典实例】

本文实例讲述了Java常用HASH算法.分享给大家供大家参考,具体如下: /** * Hash算法大全<br> * 推荐使用FNV1算法 * @algorithm None * @author Goodzzp 2006-11-20 * @lastEdit Goodzzp 2006-11-20 * @editDetail Create */ public class HashAlgorithms { /**//** * 加法hash * @param key 字符串 * @param prime

Java实现的求逆矩阵算法示例

本文实例讲述了Java实现的求逆矩阵算法.分享给大家供大家参考,具体如下: package demo; public class MatrixInverse { public static double Det(double [][]Matrix,int N)//计算n阶行列式(N=n-1) { int T0; int T1; int T2; double Num; int Cha; double [][] B; if(N>0) { Cha=0; B=new double[N][N]; Num=

Java实现的最大匹配分词算法详解

本文实例讲述了Java实现的最大匹配分词算法.分享给大家供大家参考,具体如下: 全文检索有两个重要的过程: 1分词 2倒排索引 我们先看分词算法 目前对中文分词有两个方向,其中一个是利用概率的思想对文章分词. 也就是如果两个字,一起出现的频率很高的话,我们可以假设这两个字是一个词.这里可以用一个公式衡量:M(A,B)=P(AB)/P(A)P(B),其中 A表示一个字,B表示一个字,P(AB)表示AB相邻出现的概率,P(A)表示A在这篇文章中的频度,P(B)表示B在这篇文章中的频度.用概率分词的好

多模字符串匹配算法原理及Java实现代码

多模字符串匹配算法在这里指的是在一个字符串中寻找多个模式字符字串的问题.一般来说,给出一个长字符串和很多短模式字符串,如何最快最省的求出哪些模式字符串出现在长字符串中是我们所要思考的.该算法广泛应用于关键字过滤.入侵检测.病毒检测.分词等等问题中.多模问题一般有Trie树,AC算法,WM算法等等. 背景 在做实际工作中,最简单也最常用的一种自然语言处理方法就是关键词匹配,例如我们要对n条文本进行过滤,那本身是一个过滤词表的,通常进行过滤的代码如下 for (String document : d

Java常用加密算法实例总结

本文实例总结了Java常用加密算法.分享给大家供大家参考,具体如下: 项目中第一次深入地了解到加密算法的使用,现第一阶段结束,将使用到的加密算法和大家分享一下: 首先还是先给大家普及一下常用加密算法的基础知识 基本的单向加密算法 BASE64 严格地说,属于编码格式,而非加密算法 MD5(Message Digest algorithm 5,信息摘要算法) SHA(Secure Hash Algorithm,安全散列算法) 复杂的加密算法 RSA(算法的名字以发明者的名字命名:Ron Rives

详解Java数据结构和算法(有序数组和二分查找)

一.概述 有序数组中常常用到二分查找,能提高查找的速度.今天,我们用顺序查找和二分查找实现数组的增删改查. 二.有序数组的优缺点 优点:查找速度比无序数组快多了 缺点:插入时要按排序方式把后面的数据进行移动 三.有序数组和无序数组共同优缺点 删除数据时必须把后面的数据向前移动来填补删除项的漏洞 四.代码实现 public class OrderArray { private int nElemes; //记录数组长度 private long[] a; /** * 构造函数里面初始化数组 赋值默

java编程之递归算法总结

1.何为递归 个人理解就是自己调用自己,直到满足一个条件结束自己调用自己的过程,这个就是递归.举一个通俗的点的例子: 假设你在一个电影院,你想知道自己坐在哪一排,但是前面人很多,你懒得去数了,于是你问前一排的人「你坐在哪一排?」,这样前面的人 (代号 A) 回答你以后,你就知道自己在哪一排了--只要把 A 的答案加一,就是自己所在的排了,不料 A 比你还懒,他也不想数,于是他也问他前面的人 B「你坐在哪一排?」,这样 A 可以用和你一模一样的步骤知道自己所在的排.然后 B 也如法炮制,直到他们这

Java使用分治算法实现排序数索引功能示例【二分搜索】

本文实例讲述了Java使用分治算法实现排序数索引功能.分享给大家供大家参考,具体如下: /** * Find the first q and return the index * First method is brutal force * Second may * be Divid and Conquer * * @author open201 * */ public class Ono { /** * f(n) = s.length = n; * * @param s * @param q

Java基于分治算法实现的线性时间选择操作示例

本文实例讲述了Java基于分治算法实现的线性时间选择操作.分享给大家供大家参考,具体如下: 线性时间选择问题:给定线性序集中n个元素和一个整数k,1≤k≤n,要求找出这n个元素中第k小的元素,(这里给定的线性集是无序的). 随机划分线性选择 线性时间选择随机划分法可以模仿随机化快速排序算法设计.基本思想是对输入数组进行递归划分,与快速排序不同的是,它只对划分出的子数组之一进行递归处理. 程序解释:利用随机函数产生划分基准,将数组a[p:r]划分成两个子数组a[p:i]和a[i+1:r],使a[p

Java基于分治算法实现的棋盘覆盖问题示例

本文实例讲述了Java基于分治算法实现的棋盘覆盖问题.分享给大家供大家参考,具体如下: 在一个2^k * 2^k个方格组成的棋盘中,有一个方格与其它的不同,若使用以下四种L型骨牌覆盖除这个特殊方格的其它方格,如何覆盖.四个L型骨牌如下图: 棋盘中的特殊方格如图: 实现的基本原理是将2^k * 2^k的棋盘分成四块2^(k - 1) * 2^(k - 1)的子棋盘,特殊方格一定在其中的一个子棋盘中,如果特殊方格在某一个子棋盘中,继续递归处理这个子棋盘,直到这个子棋盘中只有一个方格为止如果特殊方格不

Java编程实现游戏中的简单碰撞检测功能示例

本文实例讲述了Java编程中的简单碰撞检测功能.分享给大家供大家参考,具体如下: 今天在家正在写一个坦克大战的小游戏来玩,遇到了一个简单的圆和圆的碰撞检测的小问题, 碰撞检测的过程处理主要有以下三步: 1.碰撞检测(Collision Detection):返回两个或多个物体是否发生碰撞的布尔判断. 2.碰撞确定(Collision Determination):找到物体之间实际相交位置. 3.碰撞响应(Collision Response):针对两个物体之间的碰撞决定采取何种操作. 下面是关于

java实现从方法返回多个值功能示例

本文实例讲述了java实现从方法返回多个值功能.分享给大家供大家参考,具体如下: 这里介绍三个方法,使java方法返回多个值. 方法1:使用集合类 方法2:使用封装对象 方法3:使用引用传递 示例代码如下: import java.util.HashMap; import java.util.Map; public class Test { /** * 方法1:使用集合类 (Map以外的集合类也可以随意使用) * 目标:返回一个数组的最大值和最小值 */ public Map<String, I

java实现简单的英文文本单词翻译器功能示例

本文实例讲述了java实现简单的英文文本单词翻译器功能.分享给大家供大家参考,具体如下: 直接上代码: package fanyi; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStreamReader;

Java实现对一行英文进行单词提取功能示例

本文实例讲述了Java实现对一行英文进行单词提取功能.分享给大家供大家参考,具体如下: package fanyi; import java.util.Scanner; import java.util.StringTokenizer; public class text { public static void handle(String eString) { StringTokenizer st = new StringTokenizer(eString,",!' '.;"); w

Java实现的时间戳与date对象相互转换功能示例

本文实例讲述了Java实现的时间戳与date对象相互转换功能.分享给大家供大家参考,具体如下: 一.日期转换为时间戳 public long getTimestamp() throws ParseException{ Date date1 = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss") .parse("2009/12/11 00:00:00"); Date date2 = new SimpleDateFormat(&quo

Java Swing实现简单的体重指数(BMI)计算器功能示例

本文实例讲述了Java Swing实现简单的体重指数(BMI)计算器功能.分享给大家供大家参考,具体如下: BMI,Body Mass Index,身体质量指数,是用体重公斤数 除以 身高米数平方得出的,是目前国际上常用的衡量人体胖瘦程度以及是否健康的一个标准. 而本文通过运用Java Swing实现了一个简单的BMI计算器.虽然现在网页上也有相应的网页应用,但是能够做出这个计算器来,还是有点成就感的,希望自己以后做出更多比这个好的应用. 最终运行效果: 功能:可以选择三个标准:中国.亚洲.WH

Java实现矩阵加减乘除及转制等运算功能示例

本文实例讲述了Java实现矩阵加减乘除及转制等运算功能.分享给大家供大家参考,具体如下: Java初学,编写矩阵预算程序,当做工具,以便以后写算法时使用. public class MatrixOperation { public static int[][] add(int[][] matrix_a, int[][] matrix_b) { int row = matrix_a.length; int col = matrix_a[0].length; int[][] result = new