图像处理之玻璃水印特效(祝大家圣诞节快乐)

基本流程:

一幅文字图像,一幅目标图像,文字将会被作为水印添加到目标图像中。最终生成

一幅带水印的目标图像。

基本思想:

首先对文字图像进行预处理,扫描它的每个像素提取文字图像的水平与垂直边缘。

完成对整个文字图像扫描以后,就得到了文字图像的水平与垂直边缘数据。关于

边缘提取可以参考这里: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 ];
	}
}
转载请务必注明!

祝大家圣诞快乐!!!

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

gloomyfish

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值