图像处理之半调色融合
图像处理中错误扩散,抖动算法在在数字半调技术中有着重要的应用,是报纸,黑白
打印机等输出设备常常采用的技术。常见的图像半调技术有矩阵错误扩散,弗洛伊德-
斯坦德伯格错误扩散,空间填充曲线采样错误扩散等。本文借助半调算法,实现两张
图像的融合,将背景纹理融合到目标图像中,创造惊艳的图像处理效果。
算法基本思想:
读取纹理图像像素点P(x,y)与目标图像对应像素D(x,y),输入参数调节S取值范围[0~1]
根据参数S计算颜色差值cs = S * 255,假设像素值分别为P(x, y) =mv, D(x, y) = dv
则融合后的像素值pd(x, y)=255*(1-3x^2 - 2x^3)其中x = (mv - (dv - cs)/2cs)
运行效果:
背景图像分别为:
程序源代码:
package com.gloomyfish.filter.study; import java.awt.image.BufferedImage; /** * A filter which uses a another image as a ask to produce a halftoning effect. */ public class HalftoneFilter extends AbstractBufferedImageOp { private float softness = 0.1f; private boolean invert; private BufferedImage mask; public HalftoneFilter() { System.out.println("Stylize/Halftone..."); } /** * Set the softness of the effect in the range 0..1. * @param softness the softness * @min-value 0 * @max-value 1 */ public void setSoftness( float softness ) { this.softness = softness; } /** * Get the softness of the effect. * @return the softness * @see #setSoftness */ public float getSoftness() { return softness; } /** * Set the halftone background image. * @param BufferedImage maskImage * @see #getMask */ public void setMask( BufferedImage maskImage ) { this.mask = maskImage; } public void setInvert( boolean invert ) { this.invert = invert; } public BufferedImage filter( BufferedImage src, BufferedImage dst ) { int width = src.getWidth(); int height = src.getHeight(); if ( dst == null ) dst = createCompatibleDestImage( src, null ); if ( mask == null ) return dst; int maskWidth = mask.getWidth(); int maskHeight = mask.getHeight(); // scale to [0~255] float s = 255*softness; int[] inPixels = new int[width]; int[] maskPixels = new int[maskWidth]; for ( int y = 0; y < height; y++ ) { getRGB( src, 0, y, width, 1, inPixels ); // get row pixels getRGB( mask, 0, y % maskHeight, maskWidth, 1, maskPixels ); // get row pixels for ( int x = 0; x < width; x++ ) { int maskRGB = maskPixels[x % maskWidth]; int inRGB = inPixels[x]; if ( invert ) maskRGB ^= 0xffffff; // start to halftone here!! int ir = (inRGB >> 16) & 0xff; int ig = (inRGB >> 8) & 0xff; int ib = inRGB & 0xff; int mr = (maskRGB >> 16) & 0xff; int mg = (maskRGB >> 8) & 0xff; int mb = maskRGB & 0xff; int r = (int)(255 * (1-cubeInterpolation( ir-s, ir+s, mr ))); int g = (int)(255 * (1-cubeInterpolation( ig-s, ig+s, mg ))); int b = (int)(255 * (1-cubeInterpolation( ib-s, ib+s, mb ))); inPixels[x] = (inRGB & 0xff000000) | (r << 16) | (g << 8) | b; } setRGB( dst, 0, y, width, 1, inPixels ); } return dst; } public static float cubeInterpolation(float a, float b, float x) { if (x < a) return 0; if (x >= b) return 1; x = (x - a) / (b - a); return x*x * (3 - 2*x); } }