图像处理之仿画笔效果一
仿画笔效果最终完成自动完成从一张RGB图像到手工油画效果根据设定好的几个基本参数,
本文章解释算法的前半部分。完整的算法介绍参见这里:
http://lvelho.impa.br/ip/papers/npar2000.pdf
StrokeAreas
本文的算法主要是通过输入像素计算Color Difference与moment值得到输出像素从而得到
图像上的画笔绘画区域(StrokeArea),需要输入的参数S决定中心像素p(x,y)的相邻区域的大
小。整个处理流程本质是对输入图像的一个非线性高通滤波,结果是图像中频率越强的区域
输出越黑,频率越低的输出越白。
颜色差值(Color Difference):
表示两个像素点RGB颜色值之间的差值,计算差值采用欧几里德距离公式。
图像力矩(Image Moments),计算公式如下:
整个算法流程如下:
1. 根据输入图像生成一幅白色背景单色图像
2. 根据输入参数S计算出卷积区域大小
3. 对每个输入像素点完成卷积计算(注意是计算Color Difference)
4. 对输入像素点P0完成moment00计算
5. 归一化以后将输出像素输出到1中生成的图像对应(x,y)
程序效果:
另外一幅图效果参数s为30时候:
StrokeArea算法代码:
@Override public BufferedImage filter(BufferedImage src, BufferedImage dest) { int width = src.getWidth(); int height = src.getHeight(); if ( dest == null ) { dest = createCompatibleDestImage( src, null ); } int[] inPixels = new int[width*height]; int[] outPixels = new int[width*height]; getRGB( src, 0, 0, width, height, inPixels ); int index = 0, index2 = 0; int semiRow = (int)(size/2); int semiCol = (int)(size/2); int newX, newY; // initialize the color RGB array with zero... int[] rgb = new int[3]; int[] rgb2 = new int[3]; for(int i=0; i<rgb.length; i++) { rgb[i] = rgb2[i] = 0; } // start the algorithm process here!! for(int row=0; row<height; row++) { int ta = 0; for(int col=0; col<width; col++) { index = row * width + col; ta = (inPixels[index] >> 24) & 0xff; rgb[0] = (inPixels[index] >> 16) & 0xff; rgb[1] = (inPixels[index] >> 8) & 0xff; rgb[2] = inPixels[index] & 0xff; /* adjust region to fit in source image */ // color difference and moment Image double moment = 0.0d; for(int subRow = -semiRow; subRow <= semiRow; subRow++) { for(int subCol = -semiCol; subCol <= semiCol; subCol++) { newY = row + subRow; newX = col + subCol; if(newY < 0) { newY = 0; } if(newX < 0) { newX = 0; } if(newY >= height) { newY = height-1; } if(newX >= width) { newX = width - 1; } index2 = newY * width + newX; rgb2[0] = (inPixels[index2] >> 16) & 0xff; // red rgb2[1] = (inPixels[index2] >> 8) & 0xff; // green rgb2[2] = inPixels[index2] & 0xff; // blue moment += colorDiff(rgb, rgb2); } } // calculate the output pixel value. int outPixelValue = clamp((int) (255.0d * moment / (size*size))); outPixels[index] = (ta << 24) | (outPixelValue << 16) | (outPixelValue << 8) | outPixelValue; } } setRGB( dest, 0, 0, width, height, outPixels ); return dest; }转载文章请务必注明出自本博客