基本流程:
一幅文字图像,一幅目标图像,文字将会被作为水印添加到目标图像中。最终生成
一幅带水印的目标图像。
基本思想:
首先对文字图像进行预处理,扫描它的每个像素提取文字图像的水平与垂直边缘。
完成对整个文字图像扫描以后,就得到了文字图像的水平与垂直边缘数据。关于
边缘提取可以参考这里:http://blog.csdn.net/jia20003/article/details/7562092当
然你也可以选择其它算子然后扫描目标图像的每个像素,利用第一步计算出来的
边缘信息值作为权重值,计算每个像素上下左右的四个像素,然后完成插值计算
计算出输出像素,最终得到最后的玻璃水印效果
程序效果:
文字图像:
目标图像:
最终水印图像:
package com.gloomyfish.filter.study;
import java.awt.image.BufferedImage;
public class DisplaceFilter extends AbstractBufferedImageOp {
/**
* Treat pixels off the edge as zero.
*/
public final static int ZERO = 0;
/**
* Clamp pixels to the image edges.
*/
public final static int CLAMP = 1;
/**
* Wrap pixels off the edge onto the oppsoite edge.
*/
public final static int WRAP = 2;
/**
* Clamp pixels RGB to the image edges, but zero the alpha. This prevents gray borders on your image.
*/
public final static int RGB_CLAMP = 3;
protected int edgeAction = RGB_CLAMP;
private float amount = 1;
private BufferedImage textImage = null;
private int[] xmap, ymap;
private int dw, dh;
public DisplaceFilter() {
this(RGB_CLAMP);
}
public DisplaceFilter(int edgeAction) {
this.edgeAction = edgeAction;
}
public float getAmount() {
return amount;
}
public void setAmount(float amount) {
this.amount = amount;
}
public BufferedImage getTextImage() {
return textImage;
}
public void setTextImage(BufferedImage textInputImage) {
this.textImage = textInputImage;
}
@Override
public BufferedImage filter(BufferedImage src, BufferedImage dest) {
BufferedImage dm = textImage != null ? textImage : src;
int width = src.getWidth();
int height = src.getHeight();
if ( dest == null )
dest = createCompatibleDestImage( src, null );
dw = dm.getWidth();
dh = dm.getHeight();
int[] inPixels = new int[width*height];
int[] outPixels = new int[width*height];
getRGB( src, 0, 0, width, height, inPixels );
int[] textImagePixels = new int[dw*dh];
getRGB( dm, 0, 0, dw, dh, textImagePixels );
xmap = new int[dw*dh];
ymap = new int[dw*dh];
int i = 0;
for ( int y = 0; y < dh; y++ ) {
for ( int x = 0; x < dw; x++ ) {
int rgb = textImagePixels[i];
int r = (rgb >> 16) & 0xff;
int g = (rgb >> 8) & 0xff;
int b = rgb & 0xff;
// An arbitrary scaling factor which gives a good range
// for "amount", 16 is another optional value
textImagePixels[i] = (r+g+b) / 8;
i++;
}
}
// it is very important pre-process, extract the edge
i = 0;
for ( int y = 0; y < dh; y++ ) {
int j1 = ((y+dh-1) % dh) * dw;// row - 1
int j2 = y*dw; // row
int j3 = ((y+1) % dh) * dw; // row + 1
for ( int x = 0; x < dw; x++ ) {
int k1 = (x+dw-1) % dw; // column - 1
int k2 = x; // column
int k3 = (x+1) % dw; // column + 1
xmap[i] = textImagePixels[k1+j1] + textImagePixels[k1+j2] + textImagePixels[k1+j3] - textImagePixels[k3+j1] - textImagePixels[k3+j2] - textImagePixels[k3+j3];
ymap[i] = textImagePixels[k1+j3] + textImagePixels[k2+j3] + textImagePixels[k3+j3] - textImagePixels[k1+j1] - textImagePixels[k2+j1] - textImagePixels[k3+j1];
i++;
}
}
textImagePixels = null;
// start to process input pixel here!!!!
float[] out = new float[2];
int srcWidth = width;
int srcHeight = height;
int srcWidth1 = width-1;
int srcHeight1 = height-1;
int outdex = 0;
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
outdex = y * width + x;
transformInverse(x, y, out);
int srcX = (int)Math.floor( out[0] );
int srcY = (int)Math.floor( out[1] );
float xWeight = out[0]-srcX;
float yWeight = out[1]-srcY;
int nw, ne, sw, se;
if ( srcX >= 0 && srcX < srcWidth1 && srcY >= 0 && srcY < srcHeight1) {
// Easy case, all corners are in the image
i = srcWidth*srcY + srcX;
nw = inPixels[i];
ne = inPixels[i+1];
sw = inPixels[i+srcWidth];
se = inPixels[i+srcWidth+1];
} else {
// Some of the corners are off the image
nw = getPixel( inPixels, srcX, srcY, srcWidth, srcHeight );
ne = getPixel( inPixels, srcX+1, srcY, srcWidth, srcHeight );
sw = getPixel( inPixels, srcX, srcY+1, srcWidth, srcHeight );
se = getPixel( inPixels, srcX+1, srcY+1, srcWidth, srcHeight );
}
//双线性插值
outPixels[outdex] = ImageMath.bilinearInterpolate(xWeight, yWeight, nw, ne, sw, se);
}
}
// 返回最终结果
setRGB( dest, 0, 0, width, height, outPixels );
xmap = ymap = null;
return dest;
}
/**
*
* @param x
* @param y
* @param out
*/
protected void transformInverse(int x, int y, float[] out) {
int i = (y % dh)*dw + x % dw;
out[0] = x + amount * xmap[i];
out[1] = y + amount * ymap[i];
}
final private int getPixel( int[] pixels, int x, int y, int width, int height ) {
if (x < 0 || x >= width || y < 0 || y >= height) {
switch (edgeAction) {
case ZERO:
default:
return 0;
case WRAP:
return pixels[(ImageMath.mod(y, height) * width) + ImageMath.mod(x, width)];
case CLAMP:
return pixels[(ImageMath.clamp(y, 0, height-1) * width) + ImageMath.clamp(x, 0, width-1)];
case RGB_CLAMP:
return pixels[(ImageMath.clamp(y, 0, height-1) * width) + ImageMath.clamp(x, 0, width-1)] & 0x00ffffff;
}
}
return pixels[ y*width+x ];
}
}
转载请务必注明!
祝大家圣诞快乐!!!