图像处理之背景虚化

废话不多说,先上图。

原图

圆形的清晰区域

水平的清晰区域

竖直的清晰区域

嘿嘿,看上去还可以哈~~我们这里说的背景虚化呢,自然没有能力做到自动识别背景与前景的,所以只能算是一个半自动的过程:由用户来指定哪片区域是清晰的,哪片区域是模糊的,然后在清晰的区域与模糊的区域之间做一个简单的过渡。

我们在这里提供了三张模式,分别是圆形的清晰区域,竖直的清晰区域和水平的清晰区域。示意图如下所示

圆形

横向

纵向

如果你还想折腾出其他的形状,可以参考我后面的代码自己折腾一下。

这里不打算讲高斯模糊之类的东西,相信现有的博客写高斯模糊早已写烂了。我也只是借用了图像模糊里面的一个思想而已:使用周围像素的平均值来代替当前像素。高斯模糊里面对像素点周围不同位置的像素点还赋予了不同的权重,我为了简单,索性让所有的权重都一样。产生的效果也还行。

下面就把全部代码都奉上。

package algorithm.blur;

import java.awt.Color;
import java.awt.image.BufferedImage;

public class InteractiveBlur
{

	// 掩码最小值
	public static final int MIN_MASK_SIZE = 3;

	// 掩码最大值
	public static final int MAX_MASK_SIZE = 15;

	//掩码最大值的一半
	public static final int HALF_MAX_MASK_SIZE = 7;

	// 最小值与最大值的差
	public static final int DIFF_MASK_SIZE = MAX_MASK_SIZE - MIN_MASK_SIZE;

	// 点在模糊区域中
	public static final int AREA_BLUR = 1;

	// 点在清晰区域中
	public static final int AREA_CLEAR = 2;

	// 点在过渡区域中
	public static final int AREA_TRAN = 3;

	// 圆形的清晰区域
	public static final int TYPE_CIRCLE = 1;

	// 垂直的清晰区域
	public static final int TYPE_VERTCIAL = 2;

	// 水平的清晰区域
	public static final int TYPE_HORIZONTAL = 3;

	//外部区域以外的都是模糊的
	private static int outSize;

	//内部区域以内的都是清晰的
	private static int innerSize;

	//区域
	private static int area;

	private static Color[][] colorMatrix;

	/**
	 * 获取图像
	 *
	 * @param image
	 *            源图像
	 * @param x
	 *            x坐标
	 * @param y
	 *            y坐标
	 * @param size
	 *            作用范围
	 * @param type
	 *            类型
	 * */
	public static BufferedImage getImage(BufferedImage image, int x, int y, int size, int type)
	{
		InteractiveBlur.innerSize = size;
		InteractiveBlur.outSize = (int) (size * 1.5);
		// 获取rgb矩阵
		colorMatrix = getColorMatrix(image);

		switch (type)
		{
		case TYPE_VERTCIAL:
			return getVecticalImage(image, x, size);
		case TYPE_HORIZONTAL:
			return getHozizontalImage(image, y, size);
		default:
			return getCircleImage(image, x, y, size);
		}
	}

	/**
	 * 获取圆形的清晰区域
	 *
	 * @param image
	 *            源图像
	 * @param x
	 *            x坐标
	 * @param y
	 *            y坐标
	 * @param size
	 *            作用范围
	 * */
	private static BufferedImage getCircleImage(BufferedImage image, int centerX, int centerY, int size)
	{
		int width = image.getWidth();
		int height = image.getHeight();

		BufferedImage outputImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);

		for (int y = HALF_MAX_MASK_SIZE; y < height - HALF_MAX_MASK_SIZE; y++)
		{
			for (int x = HALF_MAX_MASK_SIZE; x < width - HALF_MAX_MASK_SIZE; x++)
			{
				int distance = getDistance(x, y, centerX, centerY);
				area = getArea(distance);
				outputImage.setRGB(x, y, getRGBValue(image, x, y,distance));
			}
		}
		return outputImage;
	}

	/**
	 * 获取纵向的背景虚化图像
	 *
	 * @param image
	 *            源图像
	 * @param x
	 *            x坐标
	 * @param y
	 *            y坐标
	 * @param size
	 *            作用范围
	 * */
	public static BufferedImage getVecticalImage(BufferedImage image, int centerX, int size)
	{
		int width = image.getWidth();
		int height = image.getHeight();

		BufferedImage outputImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);

		for (int x = HALF_MAX_MASK_SIZE; x < width - HALF_MAX_MASK_SIZE; x++)
		{
			int distance  = Math.abs(x - centerX);
			area = getArea(Math.abs(x - centerX));

			for (int y = HALF_MAX_MASK_SIZE; y < height - HALF_MAX_MASK_SIZE; y++)
			{
				outputImage.setRGB(x, y, getRGBValue(image, x, y,distance));

			}
		}
		return outputImage;
	}

	/**
	 * 获取水平的背景虚化图像
	 *
	 * @param image
	 *            源图像
	 * @param x
	 *            x坐标
	 * @param y
	 *            y坐标
	 * @param size
	 *            作用范围
	 * */
	public static BufferedImage getHozizontalImage(BufferedImage image, int centerY, int size)
	{
		int width = image.getWidth();
		int height = image.getHeight();
		BufferedImage outputImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);

		for (int y = HALF_MAX_MASK_SIZE; y < height - HALF_MAX_MASK_SIZE; y++)
		{
			int distance = Math.abs(y - centerY);
			area = getArea(distance);

			for (int x = HALF_MAX_MASK_SIZE; x < width - HALF_MAX_MASK_SIZE; x++)
			{
				outputImage.setRGB(x, y, getRGBValue(image, x, y,distance));

			}
		}
		return outputImage;
	}

	private static int getRGBValue(BufferedImage image, int x, int y,int distance)
	{
		if (area == AREA_BLUR)
		{
			return getBlurRGBValue(x, y, MAX_MASK_SIZE);
		}
		else if (area == AREA_TRAN)
		{
			// 过渡区间
			int maskSize = MIN_MASK_SIZE + DIFF_MASK_SIZE * (distance - innerSize) / (outSize - innerSize);
			// 将masksize变为奇数
			maskSize = (maskSize / 2) * 2 + 1;

			return getBlurRGBValue(x, y, maskSize);
		}
		else
		{
			return image.getRGB(x, y);
		}
	}

	/**
	 * 获取模糊后的图像的rgb值
	 *
	 * @param colorMatrix
	 * @param x
	 * @param y
	 * @param maskSize
	 * */
	private static int getBlurRGBValue(int x, int y, int maskSize)
	{
		int sum = maskSize * maskSize;
		int halfMaskSize = maskSize / 2;

		int sumR = 0, sumG = 0, sumB = 0;
		for (int i = -halfMaskSize; i <= halfMaskSize; i++)
		{
			for (int j = -halfMaskSize; j <= halfMaskSize; j++)
			{
				sumR += colorMatrix[x + i][y + j].getRed();
				sumG += colorMatrix[x + i][y + j].getGreen();
				sumB += colorMatrix[x + i][y + j].getBlue();
			}
		}
		sumR /= sum;
		sumG /= sum;
		sumB /= sum;

		sumR = sumR << 16;
		sumG = sumG << 8;

		return sumR|sumG|sumB;
	}

	// 判断点在那个区域
	private static int getArea(int distance)
	{
		int area;
		if (distance > outSize)
		{
			area = AREA_BLUR;
		}
		else if (distance < innerSize)
		{
			area = AREA_CLEAR;
		}
		else
		{
			area = AREA_TRAN;
		}
		return area;
	}

	/**
	 * 获取两点之间的距离
	 *
	 * @param x1
	 *            第一个点的X坐标
	 * @param y1
	 *            第一个点的y坐标
	 * @param x2
	 *            第二个点的X坐标
	 * @param y2
	 *            第二个点的y坐标
	 * */
	private static int getDistance(int x1, int y1, int x2, int y2)
	{
		int x = x1 - x2;
		int y = y1 - y2;
		return (int) Math.sqrt(x * x + y * y);
	}

	/**
	 * 获取图像的color矩阵
	 *
	 * @param image
	 * */
	private static Color[][] getColorMatrix(BufferedImage image)
	{
		int width = image.getWidth();
		int height = image.getHeight();
		Color[][] matrix = new Color[width][height];
		for (int y = 0; y < height; y++)
		{
			for (int x = 0; x < width; x++)
			{
				matrix[x][y]  = new Color(image.getRGB(x, y));
			}
		}
		return matrix;
	}
}
				
时间: 2024-12-25 03:35:32

图像处理之背景虚化的相关文章

opencv图像处理之在手机上实现背景虚化

http://m.blog.csdn.net/blogercn/article/details/75004162 1.高端数码相机都具有背景虚化功能.背景虚化就是使景深变浅,使焦点聚集在主题上.一般的相机最好的虚拟方法便是用微距拍摄,如果主景与背景相距比较远,由于光学透镜对非焦点处景物的不能清晰成像的特点,可以免强实现类似虚化效果.如下. 2.相机拍摄背景虚化照片一般需要经过四个步骤: (1)使变焦倍率(焦距)尽可能大: (2)拍摄物与背景尽可能距离远: (3)镜头与拍摄物尽可能距离近: (4)

实现图片模糊(背景虚化)

图片模糊效果 背景虚化(模糊)的效果越来越常用,那么如何使用代码来实现呢?在上篇文章中,我们讨论了关于 CoreImage 的知识, 理所当然的,首先尝试使用 CoreImage 解决问题,从上次打印出来的所有支持的滤镜中,在 127种滤镜中,存在 Blur 关键字的,只有CIGaussianBlur(高斯模糊),,而这种模糊的致命缺陷是,会出现白边.(懂美术的同学可能知道,这是位图和矢量图的原因) 高斯模糊代码 CIContext *context = [CIContext contextWi

UIView点击事件。弹出视图,背景虚化。

@interface CountryViewController //背景 @property (strong, nonatomic) UIView *BackView; end //设置背景虚化 -(UIView *)BackView{ if (!_BackView) { _BackView = [[UIView alloc]initWithFrame:self.view.bounds]; //背景虚化 UIColor *myColor = [UIColor colorWithWhite:0.

android 中毛玻璃效果(背景虚化)的实现

搜集很多关于背景虚化的帖子, @IcyFox 的见解 : 模糊实现方案探究 1. RenderScript 谈到高斯模糊,第一个想到的就是RenderScript.RenderScript是由Android3.0引入,用来在Android上编写高性能代码的一种语言(使用C99标准). 引用官方文档的描述: RenderScript runtime will parallelize work across all processors available on a device, such as

图像背景虚化

背景 在一幅摄影作品中,背景虚化可以很好地烘托主体,但是对于一些摄影爱好者来说,大光圈太贵:长焦镜头使用时限制太多:手中相机功能太低--虽条件不足,但又很想拍出主体突出.背景虚化的照片,这时候该怎么办呢?接下来本文简要介绍背景虚化的步骤. 步骤 抠图得到图像的前景区域 对背景使用高斯模糊,得到图层 将原图前景区域叠加到第二步得到的图层对应区域 注:第一步中,可以使用的抠图算法很多,你可以在这里寻找. 第二步中,最好使用一些保边模糊的滤波器,这里我使用Domain Transform filter

仿网易云音乐播放器(磁盘转圈、背景虚化等等)

先看效果,CSDN的git传上去总是不动.不知道为什么. 主要思路: 1 . 除了 開始/暂停 .上一首.下一首 这三个icon.你看到的是一个ViewGroup ,这个ViewGroup里面有圆形封面.黑色圈圈磁盘.唱针,高斯模糊背景图 2. 凝视掉了磁盘一起转动的效果,如今的方案不是最好的,建议若是想实现,能够把圆形封面和磁盘合并成一张图(最好在CicicleImageView这里面做).给一个旋转动画.两个动画.两个View,帧的频率不会那么高 3.凝视掉了上一首.下一首切换的时候渐变的动

背景虚化 高斯模糊

coreImage是IOS5中新加入的一个Objective-C的框架,提供了强大高效的图像处理功能,用来对基于像素的图像进行操作与分析.iOS提供了很多强大的滤镜(Filter),现在有127种之多,随着框架的更新,这一数字会继续增加.这些Filter提供了各种各样的效果,并且还可以通过滤镜链将各种效果的Filter叠加起来,形成强大的自定义效果,如果你对该效果很满意,还可以子类化滤镜.下面将代码贴在下面,与大家分享,如果对框架不熟悉,建议阅读苹果的官方API. CIContext *cont

cocos2d-x3.2中用shader使图片背景透明

今天有人问我问题,说怎么实现背景虚化,换句话说,就是把某张图片的背景颜色(比如白色)给弄没了,不然贴在屏幕上有白色背景.下面是解决方法.用shader处理了像素,使黑色背景透明. Shader.h #ifndef __TestShader__ShaderSprite__ #define __TestShader__ShaderSprite__ #include "cocos2d.h" USING_NS_CC; class ShaderSprite : public CCSprite {

图像处理与机器视觉行业分析

图像处理与机器视觉 一 行业分析 数字图像处理是对图像进行分析.加工.和处理,使其满足视觉.心理以及其他要求的技术.图像处理是信号处理在图像域上的一个应用.目前大多数的图像是以数字形式 存储,因而图像处理很多情况下指数字图像处理.此外,基于光学理论的处理方法依然占有重要的地位. 数字图像处理是信号处理的子类, 另外与计算机科学.人工智能等领域也有密切的关系. 传统的一维信号处理的方法和概念很多仍然可以直接应用在图像处理上,比如降噪.量化等.然而,图像属于二维信号,和一维信号相比,它有自己特殊的一