Java对图像的处理,具有相当强的表现能力,下列程序可以将普通照片生成类似于手绘的素描。
import java.awt.color.ColorSpace;
import java.awt.image.BufferedImage;
import java.awt.image.ColorConvertOp;
import java.io.File;
import javax.imageio.ImageIO;
public class sketch {
public static void main(String[] args) throws Exception{
String file1 = "D:/1.jpg";//原文件
String file2 = "D:/2.jpg";//素描
File inputFile = new File(file1);
BufferedImage old = ImageIO.read(inputFile);
//去色
BufferedImage b1 = discolor(old);
//反相
b1 = invert(b1);
//高斯模糊
float[][] matric = gaussian2DKernel(3, 3f);
b1 = convolution(b1, matric);
//叠加
b1 = deceaseColorCompound(old, b1);
//黑白
ColorSpace cs1 = ColorSpace.getInstance(ColorSpace.CS_GRAY);
ColorConvertOp op1 = new ColorConvertOp(cs1, null);
BufferedImage b2 = new BufferedImage(old.getWidth(), old.getHeight(), BufferedImage.TYPE_INT_RGB);
op1.filter(b1, b2);
ImageIO.write(b2, "jpg", new File(file2));
System.out.println("生成素描");
}
//去色
public static BufferedImage discolor(final BufferedImage sourceImage) {
final int width = sourceImage.getWidth();
final int height = sourceImage.getHeight();
final BufferedImage retImage = new BufferedImage(width, height,
BufferedImage.TYPE_INT_ARGB);
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
final int color1 = sourceImage.getRGB(i, j);
final int a1 = (color1 >> 24) & 0xff;
final int r1 = (color1 >> 16) & 0xff;
final int g1 = (color1 >> 8) & 0xff;
final int b1 = color1 & 0xff;
double sumA = a1;
double sumR = 0;
double sumG = 0;
double sumB = 0;
sumR = sumG = sumB = r1 * 0.299 + g1 * 0.587 + b1 * 0.114;
final int result = (((int) sumA)<<24)
| (((int) sumR) << 16) | (((int) sumG) << 8) | ((int) sumB);
retImage.setRGB(i, j, result);
}
}
return retImage;
}
//反相
public static BufferedImage invert(final BufferedImage sourceImage) {
final int width = sourceImage.getWidth();
final int height = sourceImage.getHeight();
final BufferedImage retImage = new BufferedImage(width, height,
BufferedImage.TYPE_INT_ARGB);
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
final int color1 = sourceImage.getRGB(i, j);
final int a1 = (color1 >> 24) & 0xff;
final int r1 = (color1 >> 16) & 0xff;
final int g1 = (color1 >> 8) & 0xff;
final int b1 = color1 & 0xff;
int a = a1;
int r = 255 - r1;
int g = 255 - g1;
int b = 255 - b1;
int result = (a << 24) | (r << 16) | (g << 8) | b;
if(result > 255) result = 255;
retImage.setRGB(i, j, result);
}
}
return retImage;
}
//叠加:两张图片颜色减淡混合
// C =MIN( A +(A×B)/(256-B),255)
public static BufferedImage deceaseColorCompound(final BufferedImage sourceImage,
final BufferedImage targetImage) {
final int width = sourceImage.getWidth() > targetImage.getWidth() ? sourceImage
.getWidth() : targetImage.getWidth();
final int height = sourceImage.getHeight() > targetImage.getHeight() ? sourceImage
.getHeight() : targetImage.getHeight();
final BufferedImage retImage = new BufferedImage(width, height,
BufferedImage.TYPE_INT_ARGB);
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
if(i>=sourceImage.getWidth() || j>=sourceImage.getHeight()){
if(i>=targetImage.getWidth() || j>=targetImage.getHeight()){
retImage.setRGB(i, j, 0);
continue;
}
retImage.setRGB(i, j, targetImage.getRGB(i, j));
continue;
}
if(i>=targetImage.getWidth() || j>=targetImage.getHeight()){
retImage.setRGB(i, j, sourceImage.getRGB(i, j));
continue;
}
final int color1 = sourceImage.getRGB(i, j);
final int color2 = targetImage.getRGB(i, j);
final int a1 = (color1 >> 24) & 0xff;
final int r1 = (color1 >> 16) & 0xff;
final int g1 = (color1 >> 8) & 0xff;
final int b1 = color1 & 0xff;
final int a2 = (color2 >> 24) & 0xff;
final int r2 = (color2 >> 16) & 0xff;
final int g2 = (color2 >> 8) & 0xff;
final int b2 = color2 & 0xff;
final int a = deceaseColorChannel(a1, a2);
final int r = deceaseColorChannel(r1, r2);
final int g = deceaseColorChannel(g1, g2);
final int b = deceaseColorChannel(b1, b2);
final int result = (a << 24) | (r << 16) | (g << 8) | b;
retImage.setRGB(i, j, result);
}
}
return retImage;
}
// C =MIN( A +(A×B)/(256-B),255)
private static int deceaseColorChannel(final int source, final int target) {
final int result = source + source * target / (256 - target);
return result > 255 ? 255 : result;
}
//高斯模糊
public static BufferedImage convolution(final BufferedImage image,
final float kernel[][]) {
final int width = image.getWidth();
final int height = image.getHeight();
final int radius = kernel.length / 2;
final BufferedImage retImage = new BufferedImage(width, height,
BufferedImage.TYPE_INT_ARGB);
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
double sumA = 0;
double sumR = 0;
double sumG = 0;
double sumB = 0;
for (int x = i - radius; x <= i + radius; x++) {
for (int y = j - radius; y <= j + radius; y++) {
final int posX = x < 0 ? 0 : x >= width ? width - 1 : x;
final int posY = y < 0 ? 0 : y >= height ? height - 1
: y;
final int color = image.getRGB(posX, posY);
final int a = (color >> 24) & 0xff;
final int r = (color >> 16) & 0xff;
final int g = (color >> 8) & 0xff;
final int b = color & 0xff;
final int kelX=x - i + radius;
final int kelY=y - j + radius;
sumA += kernel[kelX][kelY] * a;
sumR += kernel[kelX][kelY] * r;
sumG += kernel[kelX][kelY] * g;
sumB += kernel[kelX][kelY] * b;
}
}
final int blurColor = (((int) sumA)<<24)
| (((int) sumR) << 16) | (((int) sumG) << 8) | ((int) sumB);
retImage.setRGB(i, j, blurColor);
}
}
return retImage;
}
//2D高斯卷积矩阵
// G(x,y)=[1/(2*PI*sigma^2)]*e^[-((x^2+y^2)/(2*sigma^2))]
// x,y->[-radius,radius)
public static float[][] gaussian2DKernel(final int radius, final float sigma) {
final int length = 2 * radius;
final float[][] matric = new float[length + 1][length + 1];
final float sigmaSquare2 = 2 * sigma * sigma;
float sum = 0;
for (int x = -radius; x <= radius; x++) {
for (int y = -radius; y <= radius; y++) {
matric[radius + x][radius + y] = (float) (Math.pow(Math.E, -(x
* x + y * y)
/ sigmaSquare2) / (Math.PI * sigmaSquare2));
sum += matric[radius + x][radius + y];
}
}
for (int x = 0; x < length; x++) {
for (int y = 0; y < length; y++) {
matric[x][y] /= sum;
}
}
return matric;
}
}
生成效果比较
生成前照片:
生成后素描: