废话不多说,先上图。
原图
圆形的清晰区域
水平的清晰区域
竖直的清晰区域
嘿嘿,看上去还可以哈~~我们这里说的背景虚化呢,自然没有能力做到自动识别背景与前景的,所以只能算是一个半自动的过程:由用户来指定哪片区域是清晰的,哪片区域是模糊的,然后在清晰的区域与模糊的区域之间做一个简单的过渡。
我们在这里提供了三张模式,分别是圆形的清晰区域,竖直的清晰区域和水平的清晰区域。示意图如下所示
圆形
横向
纵向
如果你还想折腾出其他的形状,可以参考我后面的代码自己折腾一下。
这里不打算讲高斯模糊之类的东西,相信现有的博客写高斯模糊早已写烂了。我也只是借用了图像模糊里面的一个思想而已:使用周围像素的平均值来代替当前像素。高斯模糊里面对像素点周围不同位置的像素点还赋予了不同的权重,我为了简单,索性让所有的权重都一样。产生的效果也还行。
下面就把全部代码都奉上。
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;
}
}
原文地址:http://blog.csdn.net/xiayang1023/article/details/41625581