首页 > 代码库 > 图像处理之背景虚化

图像处理之背景虚化

废话不多说,先上图。

原图


圆形的清晰区域


水平的清晰区域


竖直的清晰区域


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

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

圆形


横向


纵向


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

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

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


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;
	}
}


图像处理之背景虚化