android图像处理油画

2014-01-28 22:54:58 jia20003 阅读数 9499

基于像素权重实现图像的像素模糊从而达到近似油画效果模糊

其实卷积的变种,不是基于Stroke维诺图算法与采样moment算法

模拟实现。不想跟多的废话了,先看效果:


说实话,货是干货,但是不想再多写罗嗦话,自己看代码吧!滤镜代码:

package com.gloomyfish.nature.filter.study;

import java.awt.image.BufferedImage;

import com.gloomyfish.filter.study.AbstractBufferedImageOp;

public class OilPaintFilter extends AbstractBufferedImageOp {

	private int radius = 5; // default value
	private int intensity = 20; // default value

	public OilPaintFilter(int radius, int graylevel) {
		this.radius = radius;
		this.intensity = graylevel;
	}

	public OilPaintFilter() {
		this(5, 20);
	}

	public int getRadius() {
		return radius;
	}

	public void setRadius(int radius) {
		this.radius = radius;
	}

	public int getIntensity() {
		return intensity;
	}

	public void setIntensity(int intensity) {
		this.intensity = intensity;
	}

	@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;
        int subradius = this.radius / 2;
        int[] intensityCount = new int[intensity+1];
        int[] ravg = new int[intensity+1];
        int[] gavg = new int[intensity+1];
        int[] bavg = new int[intensity+1];
        for(int i=0; i<=intensity; i++)
        {
        	intensityCount[i] = 0;
        	ravg[i] = 0;
        	gavg[i] = 0;
        	bavg[i] = 0;
        }
        for(int row=0; row<height; row++) {
        	int ta = 0, tr = 0, tg = 0, tb = 0;
        	for(int col=0; col<width; col++) {
        		
        		for(int subRow = -subradius; subRow <= subradius; subRow++)
        		{
        			for(int subCol = -subradius; subCol <= subradius; subCol++)
        			{
        				int nrow = row + subRow;
        				int ncol = col + subCol;
        				if(nrow >=height || nrow < 0)
        				{
        					nrow = 0;
        				}
        				if(ncol >= width || ncol < 0)
        				{
        					ncol = 0;
        				}
        				index = nrow * width + ncol;
	                    tr = (inPixels[index] >> 16) & 0xff;
	                    tg = (inPixels[index] >> 8) & 0xff;
	                    tb = inPixels[index] & 0xff;
	                    int curIntensity = (int)(((double)((tr+tg+tb)/3)*intensity)/255.0f);
	            		intensityCount[curIntensity]++;
	            		ravg[curIntensity] += tr;
	            		gavg[curIntensity] += tg;
	            		bavg[curIntensity] += tb;
        			}
        		}
        		
        		// find the max number of same gray level pixel
        		int maxCount = 0, maxIndex = 0;
        		for(int m=0; m<intensityCount.length; m++)
        		{
        			if(intensityCount[m] > maxCount)
        			{
        				maxCount = intensityCount[m];
        				maxIndex = m;
        			}
        		}
        		
        		// get average value of the pixel
        		int nr = ravg[maxIndex] / maxCount;
        		int ng = gavg[maxIndex] / maxCount;
        		int nb = bavg[maxIndex] / maxCount;
        		index = row * width + col;
        		outPixels[index] = (ta << 24) | (nr << 16) | (ng << 8) | nb;
        		
        		// post clear values for next pixel
                for(int i=0; i<=intensity; i++)
                {
                	intensityCount[i] = 0;
                	ravg[i] = 0;
                	gavg[i] = 0;
                	bavg[i] = 0;
                }
                
        	}
        }
        setRGB( dest, 0, 0, width, height, outPixels );
        return dest;
	}

}
最后:

祝各位新春快乐,阖家欢乐!谢谢过去一年你们对本博客的关注与支持!

2014-05-06 12:24:20 dangxw_ 阅读数 3622

转载文章请注明出处:http://blog.csdn.net/dangxw_/article/details/25063673

前些天在github上得到一个关于图像处理的源码(地址找不到了),挺全面,闲了分享一下。感谢开源。

对于图片的反转,倾斜,缩放之类的操作就不提了,网上太多了。大多都是用的Matrix现成方法。

原图:


一:圆角处理

效果:

代码

public static Bitmap getRoundedCornerBitmap(Bitmap bitmap, float roundPx)
	{

		Bitmap output = Bitmap.createBitmap(bitmap.getWidth(),
				bitmap.getHeight(), Config.ARGB_8888);
		Canvas canvas = new Canvas(output);

		final int color = 0xff424242;
		final Paint paint = new Paint();
		final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
		final RectF rectF = new RectF(rect);

		paint.setAntiAlias(true);
		canvas.drawARGB(0, 0, 0, 0);
		paint.setColor(color);
		canvas.drawRoundRect(rectF, roundPx, roundPx, paint);

		paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
		canvas.drawBitmap(bitmap, rect, rect, paint);

		return output;
	}

  理解:

这个就简单了,实际上是在原图片上画了一个圆角遮罩。对于paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));方法我刚看到也是一知半解Mode.SRC_IN参数是个画图模式,该类型是指只显示两层图案的交集部分,且交集部位只显示上层图像。实际就是先画了一个圆角矩形的过滤框,于是形状有了,再将框中的内容填充为图片。该参数总过有十八种:

public static final PorterDuff.Mode ADD

public static final PorterDuff.Mode CLEAR

public static final PorterDuff.Mode DST

public static final PorterDuff.Mode DST_ATOP

public static final PorterDuff.Mode DST_IN

and so on;

是区分不同的画图叠加效果,这个人的博客讲的很清楚:http://www.cnblogs.com/sank615/archive/2013/03/12/2955675.html。我也没做demo,所以不啰嗦了。

二:灰白处理

效果:

代码

public static Bitmap toGrayscale(Bitmap bmpOriginal)
	{
		int width, height;
		height = bmpOriginal.getHeight();
		width = bmpOriginal.getWidth();

		Bitmap bmpGrayscale = Bitmap.createBitmap(width, height,
				Bitmap.Config.RGB_565);
		Canvas c = new Canvas(bmpGrayscale);
		Paint paint = new Paint();
		ColorMatrix cm = new ColorMatrix();
		cm.setSaturation(0);
		ColorMatrixColorFilter f = new ColorMatrixColorFilter(cm);
		paint.setColorFilter(f);
		c.drawBitmap(bmpOriginal, 0, 0, paint);
		return bmpGrayscale;
	}
理解:

这个也没什么好说的,就是利用了ColorMatrix 类自带的设置饱和度的方法setSaturation()。不过其方法内部实现的更深一层是利用颜色矩阵的乘法实现的,对于颜色矩阵的乘法下面还有使用。

三 黑白处理

效果:

代码

public static Bitmap toHeibai(Bitmap mBitmap)
	{
		int mBitmapWidth = 0;
		int mBitmapHeight = 0;

		mBitmapWidth = mBitmap.getWidth();
		mBitmapHeight = mBitmap.getHeight();
		Bitmap bmpReturn = Bitmap.createBitmap(mBitmapWidth, mBitmapHeight,
				Bitmap.Config.ARGB_8888);
		int iPixel = 0;
		for (int i = 0; i < mBitmapWidth; i++)
		{
			for (int j = 0; j < mBitmapHeight; j++)
			{
				int curr_color = mBitmap.getPixel(i, j);

				int avg = (Color.red(curr_color) + Color.green(curr_color) + Color
						.blue(curr_color)) / 3;
				if (avg >= 100)
				{
					iPixel = 255;
				}
				else
				{
					iPixel = 0;
				}
				int modif_color = Color.argb(255, iPixel, iPixel, iPixel);

				bmpReturn.setPixel(i, j, modif_color);
			}
		}
		return bmpReturn;
	}

理解:

其实看图片效果就能看出来,这张图片不同于灰白处理的那张,不同之处是灰白处理虽然没有了颜色,但是黑白的程度层次依然存在,而此张图片连层次都没有了,只有两个区别十分明显的黑白颜色。实现的算法也很简单,对于每个像素的rgb值求平均数,如果高于100算白色,低于100算黑色。不过感觉100这个标准值太大了,导致图片白色区域太多,把它降低点可能效果会更好。(作者代码方法命名竟然是汉语拼音,原来是国人写的,是不是github也记不清了,我尊重原创,但是下载地址真的忘了。另外我把作者图片换了,额……)

四:镜像处理

效果:

代码

public static Bitmap createReflectionImageWithOrigin(Bitmap bitmap)
	{
		final int reflectionGap = 4;
		int width = bitmap.getWidth();
		int height = bitmap.getHeight();

		Matrix matrix = new Matrix();
		matrix.preScale(1, -1);

		Bitmap reflectionImage = Bitmap.createBitmap(bitmap, 0, height / 2,
				width, height / 2, matrix, false);

		Bitmap bitmapWithReflection = Bitmap.createBitmap(width,
				(height + height / 2), Config.ARGB_8888);

		Canvas canvas = new Canvas(bitmapWithReflection);
		canvas.drawBitmap(bitmap, 0, 0, null);
		Paint deafalutPaint = new Paint();
		canvas.drawRect(0, height, width, height + reflectionGap, deafalutPaint);

		canvas.drawBitmap(reflectionImage, 0, height + reflectionGap, null);

		Paint paint = new Paint();
		LinearGradient shader = new LinearGradient(0, bitmap.getHeight(), 0,
				bitmapWithReflection.getHeight() + reflectionGap, 0x70ffffff,
				0x00ffffff, TileMode.CLAMP);
		paint.setShader(shader);
		// Set the Transfer mode to be porter duff and destination in
		paint.setXfermode(new PorterDuffXfermode(Mode.DST_IN));
		// Draw a rectangle using the paint with our linear gradient
		canvas.drawRect(0, height, width, bitmapWithReflection.getHeight()
				+ reflectionGap, paint);

		return bitmapWithReflection;
	}

理解

记得去年android入门时做过gallery的倒影特效,当时感觉很漂亮,想着需要作出反转和倾斜就可以了,原来他也是这么做的。原理就是将原图片反转一下,调整一   下它的颜色作出倒影效果,再将两张图片续加在一起,不过如果在反转的同时再利用Matrix加上一些倾斜角度就更好了,不过那样做的话加工后的图片的高度需要同比例计算出来,不能简单的相加了,否则就图片大小就容不下现有的像素内容。

五:加旧处理

效果:

代码:

public static Bitmap testBitmap(Bitmap bitmap)
    {
        Bitmap output = Bitmap.createBitmap(bitmap.getWidth(),
                bitmap.getHeight(), Config.RGB_565);

        Canvas canvas = new Canvas(output);

        Paint paint = new Paint();        
        ColorMatrix cm = new ColorMatrix();
        float[] array = {1,0,0,0,50,
                0,1,0,0,50,
                0,0,1,0,0,
                0,0,0,1,0};
        cm.set(array);
        paint.setColorFilter(new ColorMatrixColorFilter(cm));

        canvas.drawBitmap(bitmap, 0, 0, paint);
        return output;
    }

理解

其实每张图片的存储都是存的每个像素的rgba值,而对其操作的时候又将其四个数值定位一个5行1列的矩阵,最后一行值为1,这样一来利用矩阵对其操作确实方便了好多,矩阵的乘法可以轻松的实现某个或全部分量按比例或加常熟的增加或减少。 比如现有一张图片,其每个point的rgba值为{100,100,100,255}也就是灰色全图,我们希望其红色部位增加一倍,剩余部分增加十。就可以将其值虚拟为五行一列矩阵:{100 ,100,100,255,1} 再让这个矩阵:{2,0,0,0,0换行 0,1,0,0,10换行 0,0,1,0,10换行 0,,0,0,1,10}     乘以它。得到{  200,110,100,100} 。  这个泛黄照片的处理算法原理就是让每个像素点rg值增加50,rg值相混合就得到了黄色。

如图:

详细参见:别人的博客



六:哈哈镜处理

效果:

代码

jintArray Java_com_spore_meitu_jni_ImageUtilEngine_toHahajing
  (JNIEnv* env,jobject thiz, jintArray buf, jint width, jint height,jint centerX, jint centerY, jint radius, jfloat multiple)
{
	jint * cbuf;
		cbuf = (*env)->GetIntArrayElements(env, buf, 0);

		int newSize = width * height;
		jint rbuf[newSize]; 

		float xishu = multiple;
		int real_radius = (int)(radius / xishu);

		int i = 0, j = 0;
		for (i = 0; i < width; i++)
		{
			for (j = 0; j < height; j++)
			{
				int curr_color = cbuf[j * width + i];

				int pixR = red(curr_color);
				int pixG = green(curr_color);
				int pixB = blue(curr_color);
				int pixA = alpha(curr_color);

				int newR = pixR;
				int newG = pixG;
				int newB = pixB;
				int newA = pixA;

				int distance = (int) ((centerX - i) * (centerX - i) + (centerY - j) * (centerY - j));
				if (distance < radius * radius)
				{
					
					int src_x = (int) ((float) (i - centerX) / xishu);
					int src_y = (int) ((float) (j - centerY) / xishu);
					src_x = (int)(src_x * (sqrt(distance) / real_radius));
					src_y = (int)(src_y * (sqrt(distance) / real_radius));
					src_x = src_x + centerX;
					src_y = src_y + centerY;

					int src_color = cbuf[src_y * width + src_x];
					newR = red(src_color);
					newG = green(src_color);
					newB = blue(src_color);
					newA = alpha(src_color);
				}

				newR = min(255, max(0, newR));
				newG = min(255, max(0, newG));
				newB = min(255, max(0, newB));
				newA = min(255, max(0, newA));

				int modif_color = ARGB(newA, newR, newG, newB);
				rbuf[j * width + i] = modif_color;
			}
		}

		jintArray result = (*env)->NewIntArray(env, newSize);
		(*env)->SetIntArrayRegion(env, result, 0, newSize, rbuf);
		(*env)->ReleaseIntArrayElements(env, buf, cbuf, 0);
		return result;
}

理解:

实现原理是根据哈哈镜的半径,以中心点为圆心,每个像素点的坐标位移并扩展,离中心点越近的就扩展越大。

七:放大镜处理

直接给代码吧:

jintArray Java_com_spore_meitu_jni_ImageUtilEngine_toFangdajing
  (JNIEnv* env,jobject thiz, jintArray buf, jint width, jint height,jint centerX, jint centerY, jint radius, jfloat multiple)
{
	jint * cbuf;
	cbuf = (*env)->GetIntArrayElements(env, buf, 0);

	int newSize = width * height;
	jint rbuf[newSize]; // 鏂板浘鍍忓儚绱犲�

	float xishu = multiple;
	int real_radius = (int)(radius / xishu);

	int i = 0, j = 0;
	for (i = 0; i < width; i++)
	{
		for (j = 0; j < height; j++)
		{
			int curr_color = cbuf[j * width + i];

			int pixR = red(curr_color);
			int pixG = green(curr_color);
			int pixB = blue(curr_color);
			int pixA = alpha(curr_color);

			int newR = pixR;
			int newG = pixG;
			int newB = pixB;
			int newA = pixA;

			int distance = (int) ((centerX - i) * (centerX - i) + (centerY - j) * (centerY - j));
			if (distance < radius * radius)
			{
				// 鍥惧儚鏀惧ぇ鏁堟灉
				int src_x = (int)((float)(i - centerX) / xishu + centerX);
				int src_y = (int)((float)(j - centerY) / xishu + centerY);

				int src_color = cbuf[src_y * width + src_x];
				newR = red(src_color);
				newG = green(src_color);
				newB = blue(src_color);
				newA = alpha(src_color);
			}

			newR = min(255, max(0, newR));
			newG = min(255, max(0, newG));
			newB = min(255, max(0, newB));
			newA = min(255, max(0, newA));

			int modif_color = ARGB(newA, newR, newG, newB);
			rbuf[j * width + i] = modif_color;
		}
	}

	jintArray result = (*env)->NewIntArray(env, newSize);
	(*env)->SetIntArrayRegion(env, result, 0, newSize, rbuf);
	(*env)->ReleaseIntArrayElements(env, buf, cbuf, 0);
	return result;
}

八:浮雕处理

效果:

代码

public static Bitmap toFuDiao(Bitmap mBitmap)
	{
		

		int mBitmapWidth = 0;
		int mBitmapHeight = 0;

		mBitmapWidth = mBitmap.getWidth();
		mBitmapHeight = mBitmap.getHeight();
		Bitmap bmpReturn = Bitmap.createBitmap(mBitmapWidth, mBitmapHeight,
				Bitmap.Config.RGB_565);
		int preColor = 0;
		int prepreColor = 0;
		preColor = mBitmap.getPixel(0, 0);

		for (int i = 0; i < mBitmapWidth; i++)
		{
			for (int j = 0; j < mBitmapHeight; j++)
			{
				int curr_color = mBitmap.getPixel(i, j);
				int r = Color.red(curr_color) - Color.red(prepreColor) +127;
				int g = Color.green(curr_color) - Color.red(prepreColor) + 127;
				int b = Color.green(curr_color) - Color.blue(prepreColor) + 127;
				int a = Color.alpha(curr_color);
				int modif_color = Color.argb(a, r, g, b);
				bmpReturn.setPixel(i, j, modif_color);
				prepreColor = preColor;
				preColor = curr_color;
			}
		}

		Canvas c = new Canvas(bmpReturn);
		Paint paint = new Paint();
		ColorMatrix cm = new ColorMatrix();
		cm.setSaturation(0);
		ColorMatrixColorFilter f = new ColorMatrixColorFilter(cm);
		paint.setColorFilter(f);
		c.drawBitmap(bmpReturn, 0, 0, paint);

		return bmpReturn;
	}

理解:

观察浮雕就不难发现,其实浮雕的特点就是在颜色有跳变的地方就刻条痕迹。127,127,127为深灰色,近似于石头的颜色,此处取该颜色为底色。算法是将上一个点的rgba值减去当前点的rgba值然后加上127得到当前点的颜色。

九:底片处理

效果:

代码

jintArray Java_com_spore_meitu_jni_ImageUtilEngine_toDipian
  (JNIEnv* env,jobject thiz, jintArray buf, jint width, jint height)
{
	jint * cbuf;
	cbuf = (*env)->GetIntArrayElements(env, buf, 0);
	LOGE("Bitmap Buffer %d %d",cbuf[0],cbuf[1]);

	int newSize = width * height;
	jint rbuf[newSize];

	int count = 0;
	int preColor = 0;
	int prepreColor = 0;
	int color = 0;
	preColor = cbuf[0];

	int i = 0;
	int j = 0;
	int iPixel = 0;
	for (i = 0; i < width; i++) {
		for (j = 0; j < height; j++) {
			int curr_color = cbuf[j * width + i];

			int r = 255 - red(curr_color);
			int g = 255 - green(curr_color);
			int b = 255 - blue(curr_color);
			int a = alpha(curr_color);
			int modif_color = ARGB(a, r, g, b);
			rbuf[j * width + i] = modif_color;
		}
	}
	jintArray result = (*env)->NewIntArray(env, newSize); 
	(*env)->SetIntArrayRegion(env, result, 0, newSize, rbuf); 
	(*env)->ReleaseIntArrayElements(env, buf, cbuf, 0); 
	return result;
}
理解:

算法实现是每个点grb值取为255之差,效果也真是底片效果,但是没有想通为什么这样运算就可以得到底片。

十:油画处理

效果:

代码

public static Bitmap toYouHua(Bitmap bmpSource)
	{
		Bitmap bmpReturn = Bitmap.createBitmap(bmpSource.getWidth(),
				bmpSource.getHeight(), Bitmap.Config.RGB_565);
		int color = 0;
		int Radio = 0;
		int width = bmpSource.getWidth();
		int height = bmpSource.getHeight();

		Random rnd = new Random();
		int iModel = 10;
		int i = width - iModel;
		while (i > 1)
		{
			int j = height - iModel;
			while (j > 1)
			{
				int iPos = rnd.nextInt(100000) % iModel;
				color = bmpSource.getPixel(i + iPos, j + iPos);
				bmpReturn.setPixel(i, j, color);
				j = j - 1;
			}
			i = i - 1;
		}
		return bmpReturn;
	}
理解:

赞一下这个算法,其实应该说鄙视下自己,在看到效果图的时候,我会先猜一下原理,但是这个始终没有想出来。其实油画因为是用画笔画的,彩笔画的时候没有那么精确会将本该这点的颜色滑到另一个点处。算法实现就是取一个一定范围内的随机数,每个点的颜色是该点减去随机数坐标后所得坐标的颜色。

十一:模糊处理

效果:

代码

public static Bitmap toMohu(Bitmap bmpSource, int Blur)
	{
		int mode = 5;
		Bitmap bmpReturn = Bitmap.createBitmap(bmpSource.getWidth(),
				bmpSource.getHeight(), Bitmap.Config.ARGB_8888);
		int pixels[] = new int[bmpSource.getWidth() * bmpSource.getHeight()];
		int pixelsRawSource[] = new int[bmpSource.getWidth()
				* bmpSource.getHeight() * 3];
		int pixelsRawNew[] = new int[bmpSource.getWidth()
				* bmpSource.getHeight() * 3];

		bmpSource.getPixels(pixels, 0, bmpSource.getWidth(), 0, 0,
				bmpSource.getWidth(), bmpSource.getHeight());

        for (int k = 1; k <= Blur; k++) 
        {
			
			for (int i = 0; i < pixels.length; i++)
			{
				pixelsRawSource[i * 3 + 0] = Color.red(pixels[i]);
				pixelsRawSource[i * 3 + 1] = Color.green(pixels[i]);
				pixelsRawSource[i * 3 + 2] = Color.blue(pixels[i]);
			}
			
			int CurrentPixel = bmpSource.getWidth() * 3 + 3;
		
			for (int i = 0; i < bmpSource.getHeight() - 3; i++) 
			{
				for (int j = 0; j < bmpSource.getWidth() * 3; j++) 
				{
					CurrentPixel += 1;
					int sumColor = 0; 
					sumColor = pixelsRawSource[CurrentPixel
							- bmpSource.getWidth() * 3]; 
					sumColor = sumColor + pixelsRawSource[CurrentPixel - 3];
					sumColor = sumColor + pixelsRawSource[CurrentPixel + 3]; 
					sumColor = sumColor
							+ pixelsRawSource[CurrentPixel
									+ bmpSource.getWidth() * 3]; 
					pixelsRawNew[CurrentPixel] = Math.round(sumColor / 4);
				}
			}

			for (int i = 0; i < pixels.length; i++)
			{
				pixels[i] = Color.rgb(pixelsRawNew[i * 3 + 0],
						pixelsRawNew[i * 3 + 1], pixelsRawNew[i * 3 + 2]);
			}
		}

		bmpReturn.setPixels(pixels, 0, bmpSource.getWidth(), 0, 0,
				bmpSource.getWidth(), bmpSource.getHeight()); 
		return bmpReturn;
	}
理解:

算法实现其实是取每三点的平均值做为当前点颜色,这样看上去就变得模糊了。这个算法是三点的平均值,如果能够将范围扩大,并且不是单纯的平均值,而是加权平均肯定效果会更好。不过处理速度实在是太慢了,而Muzei这种软件在处理的时候,不仅仅速度特别快,而且还有逐渐变模糊的变化过程,应该是用opengl着色实现的。


2017-08-22 10:43:22 u011280068 阅读数 149

原文链接:点击打开链接

之前一段时间,我都在研究Android自定义View的相关知识,随着逐渐的深入,渐渐了解到了一些android图像处理的知识,主要是Bitmap,Canvas,Shader,Matric,ColorFilterXfermode的使用。所以准备写一系列文章介绍一下这些方面的知识。

图像处理相关概念介绍

 要想了解Shader的概念,首先要了解Android图像处理中几个比较重要的概念:bitmap,canvas,drawing primitive,paint。需要注意的是,上述四个词并不指android中的类,而是四个概念。
 bitmap指画布。画家画图时都需要一块画布,然后才会在画布上绘制各种形状和颜色,Android中的Bitmap就有画布的功能。比如下面这段代码。


    static Bitmap makeSrc(int w,int h) {
            Bitmap bm = Bitmap.createBitmap(w,h, Bitmap.Config.ARGB_8888);
            Canvas c = new Canvas(bm);
            Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);

            p.setColor(0xFF66AAFF);
            c.drawRect(100,100,100,100,p);
            return bm;

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

 Bitmap这里就充当一个画布的作用,之后Canvas的操作都是在这个Bitmap画布进行绘制。
 canvas是绘制操作的集合,你可以把它理解成画家的手,通过它你可以在画布上绘制各种图像和颜色。相应的在Android的Canvas类中就封装了绘制相关的各种操作,比如drawXXX系列。
 drawing primitive指绘制实体或者原始内容,比如画家绘画时可能会画一个苹果,也可能只是绘制一些线段,矩形等。这些都是绘制实体。在Android中,Path,Rect,Text,Bitmap都可以充当drawing primitive的角色,因为你都可以把它们绘制到画布上。你也可以这样理解,Canvas中的drawXXX系列函数中的XXX都是指drawing primitive。
 paint就是指画家的神奇画笔啦。Android中的Paint类就充当这个角色,我们可以通过Paint来配置画笔的颜色,粗细,纹理等。我们系列文章主要讲解的Shader,ColorFilter,Xfermode三个类都和Paint直接相关。

Shader概念介绍

 Shader,也就是所谓的着色器。它应用于计算机图形学领域,指一组提供计算机图像资源在执行绘制任务时使用的指令,用于计算图像的颜色和明暗。从技术角度来看,着色器是渲染器的一部分,它负责计算目标的颜色。以我的理解,Paint就是渲染器,Paint.setShader这个函数展示了着色器和渲染器之间的关系。下面这段代码显示了Shader的使用方式。


    String text = "Shader";
    Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.drawable.photo);
    BitmapShader bitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
    Paint paint = new Paint();
    paint.setShader(bitmapShader);
    paint.setTextSize(100);
    paint.setStrokeWidth(50);
    canvas.drawText(text,0,text.length(),150,400,paint);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

 上边的代码片段使用了BitmapShader,也就是说使用图片上相应位置的颜色进行着色。就相当于使用这个图片作为背景,字体颜色是透明色,字体在(150,400)位置进行绘制,字体最终显示的颜色就是图片中相应位置的颜色。
Shader.TileMode是指平铺模式,一共有三种类型:CLAMP,MIRROR,REPEAT。构造函数中后两个参数分别规定了当绘制实体的x或y轴范围超过一定范围时(比如BitmapShaderBitmap的大小,LinearGradient中构造函数传入的x,y值),着色器填充的行为。我们以BitmapShader为例,来讲述三种模式的区别。原图如下所示,来自于这个博客

使用的bitmap原图


    Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.drawable.img);
    BitmapShader bitmapShader = new BitmapShader(bitmap, Shader.TileMode.XXX, Shader.TileMode.XXXX);
    Paint paint = new Paint();
    paint.setShader(bitmapShader);
    canvas.drawColor(Color.GRAY);
    canvas.drawRect(0,0,800,800,paint);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

Shader.TileMode.CLAMP是边缘拉伸模式,它会拉伸边缘的一个像素来填充其他区域。效果图如下所示,我们可以看到,超出bitmap大小的范围都被图片边缘的颜色所填充。

clamp效果图

Shader.TileMode.MIRROR是镜像模式,也就是说它通过镜像变化来填充其他区域。需要注意的是,TileMode是先处理y轴方向的操作,然后在进行x轴方向的操作。也就是说先进行y轴方向的镜像操作,然后在进行x轴方向上的镜像操作。不过我觉得好像先进行哪个方向上的操作并没有什么区别,最终效果是一样的。其效果图如下所示:
mirror效果图
Shader.TileMode.REPEAT是重复模式,通过复制来填充其他区域
repeat效果图
 你也可以对x,y轴使用不同的TileMode,可以得到不同的效果。
clamp+mirro效果图

Shader类型介绍

BitmapShader的用法很简单,上边的实例中也有用到,所以我们就不再详细介绍它了。

LinearGradient

LinearGradient是颜色线性渐变的着色器。它有两个构造函数:
 双色渐变的构造函数是

public LinearGradient (float x0, float y0, float x1, float y1, int color0, int color1, Shader.TileMode tile)

 参数中,(x0,y0)表示渐变的起点,(x1,y1)表示渐变的终点坐标,这两点都是相对于屏幕坐标系。color0,color1分别表示起点的颜色和终点的颜色。不同于BitmapShader需要x,y轴两个平铺模式参数,LinearGradient只需要一个TileMode,表示从(x0,y0)到(x1,y1)方向上的平铺模式
LinearGradient的平铺效果可能比较难以理解,需要大家多做几次实验才能明白。
 下图是200*200的由红色到黄色的线性渐变效果着色器绘制200*200的矩形的效果图,着色器的TileModeMIRROR:
linegradient1
 下图是上述的着色器绘制400*400的效果图,我们可以看到二者的区别,在屏幕坐标轴的(200,200)方向(第二张图中的黑色线段所代表的方向)上颜色是先从红色到黄色,超过(200,200)这个点之后,由于设置平铺模式为MIRROR所以颜色就又从黄色逐渐变成了红色。这个对角线外上的点的颜色是和其在对角线上(-200,200)方向上的投影点的颜色相同,也就是第二张图中蓝色直线上点的颜色都是相同的。
linegradient2
linegradient5

 多色渐变的构造函数是

public LinearGradient (float x0, float y0, float x1, float y1, int[] colors, float[] positions, Shader.TileMode tile)
 多色渐变的构造函数中,我们可以传入多个颜色,和每个颜色的占比。而且当positions参数传入null时,代表颜色是均匀的填充整个渐变区域的,显得比较柔和。
linegradient

SweepGradient

SweepGradient是梯度渐变,也称为扫描式渐变,效果有点类似与雷达扫描效果。它也有两个构造方法,分别为两色渐变和多色渐变,二者的区别和之前介绍的LinearGradient的构造函数类似,我们这里就只介绍双色渐变的构造函数:

public SweepGradient(float cx, float cy, int color0, int color1)
 在构造函数的参数中,(cx,cy)表示渐变效果的中心点,也就是雷达扫描的圆点。color0和color1表示渐变的起点色和终点色。颜色渐变是顺时针的,从中心点的x轴正方形开始。需要注意的是,这里构造函数并不需要TileMode,因为梯度渐变的边界相当于无限大的。
sweepgradient

RadialGradient

RadialGradient是径向渐变,径向渐变就是从圆的中心点向四周渐变的特效,你可以把它想象成一个圆,从圆点到圆周沿着半径有颜色的渐变效果。它也有两个构造函数,我们只介绍双色渐变的构造函数。

public RadialGradient(float centerX, float centerY, float radius,
int centerColor, int edgeColor, TileMode tileMode)

 在构造函数的参数中,(centerX,centerY)表示径向渐变中的圆点,radius表示圆的半径长度,centerColor表示圆点颜色,edgeColor表示圆周颜色,titleMode表示平铺模式,它的作用方向是沿着半径方向。下图就是一个有红色到黄色的径向渐变,平铺模式为CLAMP,所以超出圆周的范围的点的颜色就都是圆周的颜色黄色。
radialgradient

ComposeShader

ComposeShader用来组合不同的Shader,可以将两个不同的Shader组合在一起,它有两个构造函数:

ComposeShader (Shader shaderA, Shader shaderB, Xfermode mode)  
ComposeShader (Shader shaderA, Shader shaderB, PorterDuff.Mode mode)  
  • 1
  • 2
  • 1
  • 2

 二者的区别就是一个使用PorterDuff的模式,另一个可以使用所有的Xfermode。这两个混合模式我们在之后的文章中将会详细讲到。

后记

 这里只是简单介绍了一下Shader的概念和基本用法,之后会多加一些实际使用的情况,希望大家持续关注。

2014-09-22 15:15:00 hewence1 阅读数 1760

转载文章请注明出处:http://blog.csdn.net/dangxw_/article/details/25063673

前些天在github上得到一个关于图像处理的源码(地址找不到了),挺全面,闲了分享一下。感谢开源。

对于图片的反转,倾斜,缩放之类的操作就不提了,网上太多了。大多都是用的Matrix现成方法。

原图:


一:圆角处理

效果:

代码

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public static Bitmap getRoundedCornerBitmap(Bitmap bitmap, float roundPx)  
  2.     {  
  3.   
  4.         Bitmap output = Bitmap.createBitmap(bitmap.getWidth(),  
  5.                 bitmap.getHeight(), Config.ARGB_8888);  
  6.         Canvas canvas = new Canvas(output);  
  7.   
  8.         final int color = 0xff424242;  
  9.         final Paint paint = new Paint();  
  10.         final Rect rect = new Rect(00, bitmap.getWidth(), bitmap.getHeight());  
  11.         final RectF rectF = new RectF(rect);  
  12.   
  13.         paint.setAntiAlias(true);  
  14.         canvas.drawARGB(0000);  
  15.         paint.setColor(color);  
  16.         canvas.drawRoundRect(rectF, roundPx, roundPx, paint);  
  17.   
  18.         paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));  
  19.         canvas.drawBitmap(bitmap, rect, rect, paint);  
  20.   
  21.         return output;  
  22.     }  

  理解:

这个就简单了,实际上是在原图片上画了一个圆角遮罩。对于paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));方法我刚看到也是一知半解Mode.SRC_IN参数是个画图模式,该类型是指只显示两层图案的交集部分,且交集部位只显示上层图像。实际就是先画了一个圆角矩形的过滤框,于是形状有了,再将框中的内容填充为图片。该参数总过有十八种:

public static final PorterDuff.Mode ADD

public static final PorterDuff.Mode CLEAR

public static final PorterDuff.Mode DST

public static final PorterDuff.Mode DST_ATOP

public static final PorterDuff.Mode DST_IN

and so on;

是区分不同的画图叠加效果,这个人的博客讲的很清楚:http://www.cnblogs.com/sank615/archive/2013/03/12/2955675.html。我也没做demo,所以不啰嗦了。

二:灰白处理

效果:

代码

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public static Bitmap toGrayscale(Bitmap bmpOriginal)  
  2.     {  
  3.         int width, height;  
  4.         height = bmpOriginal.getHeight();  
  5.         width = bmpOriginal.getWidth();  
  6.   
  7.         Bitmap bmpGrayscale = Bitmap.createBitmap(width, height,  
  8.                 Bitmap.Config.RGB_565);  
  9.         Canvas c = new Canvas(bmpGrayscale);  
  10.         Paint paint = new Paint();  
  11.         ColorMatrix cm = new ColorMatrix();  
  12.         cm.setSaturation(0);  
  13.         ColorMatrixColorFilter f = new ColorMatrixColorFilter(cm);  
  14.         paint.setColorFilter(f);  
  15.         c.drawBitmap(bmpOriginal, 00, paint);  
  16.         return bmpGrayscale;  
  17.     }  
理解:

这个也没什么好说的,就是利用了ColorMatrix 类自带的设置饱和度的方法setSaturation()。不过其方法内部实现的更深一层是利用颜色矩阵的乘法实现的,对于颜色矩阵的乘法下面还有使用。

三 黑白处理

效果:

代码

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public static Bitmap toHeibai(Bitmap mBitmap)  
  2.     {  
  3.         int mBitmapWidth = 0;  
  4.         int mBitmapHeight = 0;  
  5.   
  6.         mBitmapWidth = mBitmap.getWidth();  
  7.         mBitmapHeight = mBitmap.getHeight();  
  8.         Bitmap bmpReturn = Bitmap.createBitmap(mBitmapWidth, mBitmapHeight,  
  9.                 Bitmap.Config.ARGB_8888);  
  10.         int iPixel = 0;  
  11.         for (int i = 0; i < mBitmapWidth; i++)  
  12.         {  
  13.             for (int j = 0; j < mBitmapHeight; j++)  
  14.             {  
  15.                 int curr_color = mBitmap.getPixel(i, j);  
  16.   
  17.                 int avg = (Color.red(curr_color) + Color.green(curr_color) + Color  
  18.                         .blue(curr_color)) / 3;  
  19.                 if (avg >= 100)  
  20.                 {  
  21.                     iPixel = 255;  
  22.                 }  
  23.                 else  
  24.                 {  
  25.                     iPixel = 0;  
  26.                 }  
  27.                 int modif_color = Color.argb(255, iPixel, iPixel, iPixel);  
  28.   
  29.                 bmpReturn.setPixel(i, j, modif_color);  
  30.             }  
  31.         }  
  32.         return bmpReturn;  
  33.     }  

理解:

其实看图片效果就能看出来,这张图片不同于灰白处理的那张,不同之处是灰白处理虽然没有了颜色,但是黑白的程度层次依然存在,而此张图片连层次都没有了,只有两个区别十分明显的黑白颜色。实现的算法也很简单,对于每个像素的rgb值求平均数,如果高于100算白色,低于100算黑色。不过感觉100这个标准值太大了,导致图片白色区域太多,把它降低点可能效果会更好。(作者代码方法命名竟然是汉语拼音,原来是国人写的,是不是github也记不清了,我尊重原创,但是下载地址真的忘了。另外我把作者图片换了,额……)

四:镜像处理

效果:

代码

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public static Bitmap createReflectionImageWithOrigin(Bitmap bitmap)  
  2.     {  
  3.         final int reflectionGap = 4;  
  4.         int width = bitmap.getWidth();  
  5.         int height = bitmap.getHeight();  
  6.   
  7.         Matrix matrix = new Matrix();  
  8.         matrix.preScale(1, -1);  
  9.   
  10.         Bitmap reflectionImage = Bitmap.createBitmap(bitmap, 0, height / 2,  
  11.                 width, height / 2, matrix, false);  
  12.   
  13.         Bitmap bitmapWithReflection = Bitmap.createBitmap(width,  
  14.                 (height + height / 2), Config.ARGB_8888);  
  15.   
  16.         Canvas canvas = new Canvas(bitmapWithReflection);  
  17.         canvas.drawBitmap(bitmap, 00null);  
  18.         Paint deafalutPaint = new Paint();  
  19.         canvas.drawRect(0, height, width, height + reflectionGap, deafalutPaint);  
  20.   
  21.         canvas.drawBitmap(reflectionImage, 0, height + reflectionGap, null);  
  22.   
  23.         Paint paint = new Paint();  
  24.         LinearGradient shader = new LinearGradient(0, bitmap.getHeight(), 0,  
  25.                 bitmapWithReflection.getHeight() + reflectionGap, 0x70ffffff,  
  26.                 0x00ffffff, TileMode.CLAMP);  
  27.         paint.setShader(shader);  
  28.         // Set the Transfer mode to be porter duff and destination in  
  29.         paint.setXfermode(new PorterDuffXfermode(Mode.DST_IN));  
  30.         // Draw a rectangle using the paint with our linear gradient  
  31.         canvas.drawRect(0, height, width, bitmapWithReflection.getHeight()  
  32.                 + reflectionGap, paint);  
  33.   
  34.         return bitmapWithReflection;  
  35.     }  

理解

记得去年android入门时做过gallery的倒影特效,当时感觉很漂亮,想着需要作出反转和倾斜就可以了,原来他也是这么做的。原理就是将原图片反转一下,调整一   下它的颜色作出倒影效果,再将两张图片续加在一起,不过如果在反转的同时再利用Matrix加上一些倾斜角度就更好了,不过那样做的话加工后的图片的高度需要同比例计算出来,不能简单的相加了,否则就图片大小就容不下现有的像素内容。

五:加旧处理

效果:

代码:

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public static Bitmap testBitmap(Bitmap bitmap)  
  2.     {  
  3.         Bitmap output = Bitmap.createBitmap(bitmap.getWidth(),  
  4.                 bitmap.getHeight(), Config.RGB_565);  
  5.   
  6.         Canvas canvas = new Canvas(output);  
  7.   
  8.         Paint paint = new Paint();          
  9.         ColorMatrix cm = new ColorMatrix();  
  10.         float[] array = {1,0,0,0,50,  
  11.                 0,1,0,0,50,  
  12.                 0,0,1,0,0,  
  13.                 0,0,0,1,0};  
  14.         cm.set(array);  
  15.         paint.setColorFilter(new ColorMatrixColorFilter(cm));  
  16.   
  17.         canvas.drawBitmap(bitmap, 00, paint);  
  18.         return output;  
  19.     }  

理解

其实每张图片的存储都是存的每个像素的rgba值,而对其操作的时候又将其四个数值定位一个5行1列的矩阵,最后一行值为1,这样一来利用矩阵对其操作确实方便了好多,矩阵的乘法可以轻松的实现某个或全部分量按比例或加常熟的增加或减少。 比如现有一张图片,其每个point的rgba值为{100,100,100,255}也就是灰色全图,我们希望其红色部位增加一倍,剩余部分增加十。就可以将其值虚拟为五行一列矩阵:{100 ,100,100,255,1} 再让这个矩阵:{2,0,0,0,0换行 0,1,0,0,10换行 0,0,1,0,10换行 0,,0,0,1,10}     乘以它。得到{  200,110,100,100} 。  这个泛黄照片的处理算法原理就是让每个像素点rg值增加50,rg值相混合就得到了黄色。

如图:

详细参见:别人的博客



六:哈哈镜处理

效果:

代码

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. jintArray Java_com_spore_meitu_jni_ImageUtilEngine_toHahajing  
  2.   (JNIEnv* env,jobject thiz, jintArray buf, jint width, jint height,jint centerX, jint centerY, jint radius, jfloat multiple)  
  3. {  
  4.     jint * cbuf;  
  5.         cbuf = (*env)->GetIntArrayElements(env, buf, 0);  
  6.   
  7.         int newSize = width * height;  
  8.         jint rbuf[newSize];   
  9.   
  10.         float xishu = multiple;  
  11.         int real_radius = (int)(radius / xishu);  
  12.   
  13.         int i = 0, j = 0;  
  14.         for (i = 0; i < width; i++)  
  15.         {  
  16.             for (j = 0; j < height; j++)  
  17.             {  
  18.                 int curr_color = cbuf[j * width + i];  
  19.   
  20.                 int pixR = red(curr_color);  
  21.                 int pixG = green(curr_color);  
  22.                 int pixB = blue(curr_color);  
  23.                 int pixA = alpha(curr_color);  
  24.   
  25.                 int newR = pixR;  
  26.                 int newG = pixG;  
  27.                 int newB = pixB;  
  28.                 int newA = pixA;  
  29.   
  30.                 int distance = (int) ((centerX - i) * (centerX - i) + (centerY - j) * (centerY - j));  
  31.                 if (distance < radius * radius)  
  32.                 {  
  33.                       
  34.                     int src_x = (int) ((float) (i - centerX) / xishu);  
  35.                     int src_y = (int) ((float) (j - centerY) / xishu);  
  36.                     src_x = (int)(src_x * (sqrt(distance) / real_radius));  
  37.                     src_y = (int)(src_y * (sqrt(distance) / real_radius));  
  38.                     src_x = src_x + centerX;  
  39.                     src_y = src_y + centerY;  
  40.   
  41.                     int src_color = cbuf[src_y * width + src_x];  
  42.                     newR = red(src_color);  
  43.                     newG = green(src_color);  
  44.                     newB = blue(src_color);  
  45.                     newA = alpha(src_color);  
  46.                 }  
  47.   
  48.                 newR = min(255, max(0, newR));  
  49.                 newG = min(255, max(0, newG));  
  50.                 newB = min(255, max(0, newB));  
  51.                 newA = min(255, max(0, newA));  
  52.   
  53.                 int modif_color = ARGB(newA, newR, newG, newB);  
  54.                 rbuf[j * width + i] = modif_color;  
  55.             }  
  56.         }  
  57.   
  58.         jintArray result = (*env)->NewIntArray(env, newSize);  
  59.         (*env)->SetIntArrayRegion(env, result, 0, newSize, rbuf);  
  60.         (*env)->ReleaseIntArrayElements(env, buf, cbuf, 0);  
  61.         return result;  
  62. }  

理解:

搞不懂一个图片处理,为什么作者要加到jni那层去,速度能提升多少,赤裸裸的嘲讽我们的技术。纯c代码真懒得看,心情好的时候再看,看完了再来更新,猜测实现原理是根据哈哈镜的半径,以中心点为圆心,每个像素点的坐标位移并扩展,离中心点越近的就扩展越大。

七:放大镜处理

直接给代码吧:

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. jintArray Java_com_spore_meitu_jni_ImageUtilEngine_toFangdajing  
  2.   (JNIEnv* env,jobject thiz, jintArray buf, jint width, jint height,jint centerX, jint centerY, jint radius, jfloat multiple)  
  3. {  
  4.     jint * cbuf;  
  5.     cbuf = (*env)->GetIntArrayElements(env, buf, 0);  
  6.   
  7.     int newSize = width * height;  
  8.     jint rbuf[newSize]; // 鏂板浘鍍忓儚绱犲�  
  9.   
  10.     float xishu = multiple;  
  11.     int real_radius = (int)(radius / xishu);  
  12.   
  13.     int i = 0, j = 0;  
  14.     for (i = 0; i < width; i++)  
  15.     {  
  16.         for (j = 0; j < height; j++)  
  17.         {  
  18.             int curr_color = cbuf[j * width + i];  
  19.   
  20.             int pixR = red(curr_color);  
  21.             int pixG = green(curr_color);  
  22.             int pixB = blue(curr_color);  
  23.             int pixA = alpha(curr_color);  
  24.   
  25.             int newR = pixR;  
  26.             int newG = pixG;  
  27.             int newB = pixB;  
  28.             int newA = pixA;  
  29.   
  30.             int distance = (int) ((centerX - i) * (centerX - i) + (centerY - j) * (centerY - j));  
  31.             if (distance < radius * radius)  
  32.             {  
  33.                 // 鍥惧儚鏀惧ぇ鏁堟灉  
  34.                 int src_x = (int)((float)(i - centerX) / xishu + centerX);  
  35.                 int src_y = (int)((float)(j - centerY) / xishu + centerY);  
  36.   
  37.                 int src_color = cbuf[src_y * width + src_x];  
  38.                 newR = red(src_color);  
  39.                 newG = green(src_color);  
  40.                 newB = blue(src_color);  
  41.                 newA = alpha(src_color);  
  42.             }  
  43.   
  44.             newR = min(255, max(0, newR));  
  45.             newG = min(255, max(0, newG));  
  46.             newB = min(255, max(0, newB));  
  47.             newA = min(255, max(0, newA));  
  48.   
  49.             int modif_color = ARGB(newA, newR, newG, newB);  
  50.             rbuf[j * width + i] = modif_color;  
  51.         }  
  52.     }  
  53.   
  54.     jintArray result = (*env)->NewIntArray(env, newSize);  
  55.     (*env)->SetIntArrayRegion(env, result, 0, newSize, rbuf);  
  56.     (*env)->ReleaseIntArrayElements(env, buf, cbuf, 0);  
  57.     return result;  
  58. }  

八:浮雕处理

效果:

代码

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public static Bitmap toFuDiao(Bitmap mBitmap)  
  2.     {  
  3.           
  4.   
  5.         int mBitmapWidth = 0;  
  6.         int mBitmapHeight = 0;  
  7.   
  8.         mBitmapWidth = mBitmap.getWidth();  
  9.         mBitmapHeight = mBitmap.getHeight();  
  10.         Bitmap bmpReturn = Bitmap.createBitmap(mBitmapWidth, mBitmapHeight,  
  11.                 Bitmap.Config.RGB_565);  
  12.         int preColor = 0;  
  13.         int prepreColor = 0;  
  14.         preColor = mBitmap.getPixel(00);  
  15.   
  16.         for (int i = 0; i < mBitmapWidth; i++)  
  17.         {  
  18.             for (int j = 0; j < mBitmapHeight; j++)  
  19.             {  
  20.                 int curr_color = mBitmap.getPixel(i, j);  
  21.                 int r = Color.red(curr_color) - Color.red(prepreColor) +127;  
  22.                 int g = Color.green(curr_color) - Color.red(prepreColor) + 127;  
  23.                 int b = Color.green(curr_color) - Color.blue(prepreColor) + 127;  
  24.                 int a = Color.alpha(curr_color);  
  25.                 int modif_color = Color.argb(a, r, g, b);  
  26.                 bmpReturn.setPixel(i, j, modif_color);  
  27.                 prepreColor = preColor;  
  28.                 preColor = curr_color;  
  29.             }  
  30.         }  
  31.   
  32.         Canvas c = new Canvas(bmpReturn);  
  33.         Paint paint = new Paint();  
  34.         ColorMatrix cm = new ColorMatrix();  
  35.         cm.setSaturation(0);  
  36.         ColorMatrixColorFilter f = new ColorMatrixColorFilter(cm);  
  37.         paint.setColorFilter(f);  
  38.         c.drawBitmap(bmpReturn, 00, paint);  
  39.   
  40.         return bmpReturn;  
  41.     }  

理解:

观察浮雕就不难发现,其实浮雕的特点就是在颜色有跳变的地方就刻条痕迹。127,127,127为深灰色,近似于石头的颜色,此处取该颜色为底色。算法是将上一个点的rgba值减去当前点的rgba值然后加上127得到当前点的颜色。

九:底片处理

效果:

代码

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. jintArray Java_com_spore_meitu_jni_ImageUtilEngine_toDipian  
  2.   (JNIEnv* env,jobject thiz, jintArray buf, jint width, jint height)  
  3. {  
  4.     jint * cbuf;  
  5.     cbuf = (*env)->GetIntArrayElements(env, buf, 0);  
  6.     LOGE("Bitmap Buffer %d %d",cbuf[0],cbuf[1]);  
  7.   
  8.     int newSize = width * height;  
  9.     jint rbuf[newSize];  
  10.   
  11.     int count = 0;  
  12.     int preColor = 0;  
  13.     int prepreColor = 0;  
  14.     int color = 0;  
  15.     preColor = cbuf[0];  
  16.   
  17.     int i = 0;  
  18.     int j = 0;  
  19.     int iPixel = 0;  
  20.     for (i = 0; i < width; i++) {  
  21.         for (j = 0; j < height; j++) {  
  22.             int curr_color = cbuf[j * width + i];  
  23.   
  24.             int r = 255 - red(curr_color);  
  25.             int g = 255 - green(curr_color);  
  26.             int b = 255 - blue(curr_color);  
  27.             int a = alpha(curr_color);  
  28.             int modif_color = ARGB(a, r, g, b);  
  29.             rbuf[j * width + i] = modif_color;  
  30.         }  
  31.     }  
  32.     jintArray result = (*env)->NewIntArray(env, newSize);   
  33.     (*env)->SetIntArrayRegion(env, result, 0, newSize, rbuf);   
  34.     (*env)->ReleaseIntArrayElements(env, buf, cbuf, 0);   
  35.     return result;  
  36. }  
理解:

算法实现是每个点grb值取为255之差,效果也真是底片效果,但是没有想通为什么这样运算就可以得到底片,回头更新。

十:油画处理

效果:

代码

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public static Bitmap toYouHua(Bitmap bmpSource)  
  2.     {  
  3.         Bitmap bmpReturn = Bitmap.createBitmap(bmpSource.getWidth(),  
  4.                 bmpSource.getHeight(), Bitmap.Config.RGB_565);  
  5.         int color = 0;  
  6.         int Radio = 0;  
  7.         int width = bmpSource.getWidth();  
  8.         int height = bmpSource.getHeight();  
  9.   
  10.         Random rnd = new Random();  
  11.         int iModel = 10;  
  12.         int i = width - iModel;  
  13.         while (i > 1)  
  14.         {  
  15.             int j = height - iModel;  
  16.             while (j > 1)  
  17.             {  
  18.                 int iPos = rnd.nextInt(100000) % iModel;  
  19.                 color = bmpSource.getPixel(i + iPos, j + iPos);  
  20.                 bmpReturn.setPixel(i, j, color);  
  21.                 j = j - 1;  
  22.             }  
  23.             i = i - 1;  
  24.         }  
  25.         return bmpReturn;  
  26.     }  
理解:

赞一下这个算法,其实应该说鄙视下自己,在看到效果图的时候,我会先猜一下原理,但是这个始终没有想出来。其实油画因为是用画笔画的,彩笔画的时候没有那么精确会将本该这点的颜色滑到另一个点处。算法实现就是取一个一定范围内的随机数,每个点的颜色是该点减去随机数坐标后所得坐标的颜色。

十一:模糊处理

效果:

代码

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public static Bitmap toMohu(Bitmap bmpSource, int Blur)  
  2.     {  
  3.         int mode = 5;  
  4.         Bitmap bmpReturn = Bitmap.createBitmap(bmpSource.getWidth(),  
  5.                 bmpSource.getHeight(), Bitmap.Config.ARGB_8888);  
  6.         int pixels[] = new int[bmpSource.getWidth() * bmpSource.getHeight()];  
  7.         int pixelsRawSource[] = new int[bmpSource.getWidth()  
  8.                 * bmpSource.getHeight() * 3];  
  9.         int pixelsRawNew[] = new int[bmpSource.getWidth()  
  10.                 * bmpSource.getHeight() * 3];  
  11.   
  12.         bmpSource.getPixels(pixels, 0, bmpSource.getWidth(), 00,  
  13.                 bmpSource.getWidth(), bmpSource.getHeight());  
  14.   
  15.         for (int k = 1; k <= Blur; k++)   
  16.         {  
  17.               
  18.             for (int i = 0; i < pixels.length; i++)  
  19.             {  
  20.                 pixelsRawSource[i * 3 + 0] = Color.red(pixels[i]);  
  21.                 pixelsRawSource[i * 3 + 1] = Color.green(pixels[i]);  
  22.                 pixelsRawSource[i * 3 + 2] = Color.blue(pixels[i]);  
  23.             }  
  24.               
  25.             int CurrentPixel = bmpSource.getWidth() * 3 + 3;  
  26.           
  27.             for (int i = 0; i < bmpSource.getHeight() - 3; i++)   
  28.             {  
  29.                 for (int j = 0; j < bmpSource.getWidth() * 3; j++)   
  30.                 {  
  31.                     CurrentPixel += 1;  
  32.                     int sumColor = 0;   
  33.                     sumColor = pixelsRawSource[CurrentPixel  
  34.                             - bmpSource.getWidth() * 3];   
  35.                     sumColor = sumColor + pixelsRawSource[CurrentPixel - 3];  
  36.                     sumColor = sumColor + pixelsRawSource[CurrentPixel + 3];   
  37.                     sumColor = sumColor  
  38.                             + pixelsRawSource[CurrentPixel  
  39.                                     + bmpSource.getWidth() * 3];   
  40.                     pixelsRawNew[CurrentPixel] = Math.round(sumColor / 4);  
  41.                 }  
  42.             }  
  43.   
  44.             for (int i = 0; i < pixels.length; i++)  
  45.             {  
  46.                 pixels[i] = Color.rgb(pixelsRawNew[i * 3 + 0],  
  47.                         pixelsRawNew[i * 3 + 1], pixelsRawNew[i * 3 + 2]);  
  48.             }  
  49.         }  
  50.   
  51.         bmpReturn.setPixels(pixels, 0, bmpSource.getWidth(), 00,  
  52.                 bmpSource.getWidth(), bmpSource.getHeight());   
  53.         return bmpReturn;  
  54.     }  
理解:

算法实现其实是取每三点的平均值做为当前点颜色,这样看上去就变得模糊了。这个算法是三点的平均值,如果能够将范围扩大,并且不是单纯的平均值,而是加权平均肯定效果会更好。不过处理速度实在是太慢了,而Muzei这种软件在处理的时候,不仅仅速度特别快,而且还有逐渐变模糊的变化过程,显然人家不是用这种算法实现的。他们的实现方法正在猜测中,实现后也来更新

2018-02-01 12:35:12 u011228868 阅读数 3362
 

我们常用的处理方式基本都是在对像素矩阵按照一定的数学规律处理得到的,常用的如下;我们也可以通过一个开源的图片处理库(C++)的方式处理,opencv,官网:http://opencv.org/   下载对应平台的SDK,这个库很强大,里面基本包含了常用的处理操作,而且效率很高。对应的文字处理库是OCR(顺带提一下)。

以下是参考文献:

点击打开链接

点击打开链接

点击打开链接

这里有一个开源库很是不错:https://github.com/CyberAgent/android-gpuimage

以上是参考链接,已经很详细了,接下来我会出一个通用的demo在后期会更新上传到这篇博客上。

1、圆角图片

[java] view plain copy
  1. /** 
  2.      * 转换成圆角 
  3.      *  
  4.      * @param bmp 
  5.      * @param roundPx 
  6.      * @return 
  7.      */  
  8.     public static Bitmap convertToRoundedCorner(Bitmap bmp, float roundPx) {  
  9.         Bitmap newBmp = Bitmap.createBitmap(bmp.getWidth(), bmp.getHeight(),  
  10.                 Config.ARGB_8888);  
  11.         // 得到画布  
  12.         Canvas canvas = new Canvas(newBmp);  
  13.         final int color = 0xff424242;  
  14.         final Paint paint = new Paint();  
  15.         final Rect rect = new Rect(00, bmp.getWidth(), bmp.getHeight());  
  16.         final RectF rectF = new RectF(rect);  
  17.         paint.setAntiAlias(true);  
  18.         canvas.drawARGB(0000);  
  19.         paint.setColor(color);  
  20.         // 第二个和第三个参数一样则画的是正圆的一角,否则是椭圆的一角  
  21.         canvas.drawRoundRect(rectF, roundPx, roundPx, paint);  
  22.         paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));  
  23.         canvas.drawBitmap(bmp, rect, rect, paint);  
  24.         return newBmp;  
  25.     }  

2、图片灰度化

[java] view plain copy
  1. /** 
  2.      * 图片灰度化处理 
  3.      *  
  4.      * @param bmSrc 
  5.      * */  
  6.     public Bitmap bitmap2Gray(Bitmap bmSrc) {  
  7.         // 得到图片的长和宽  
  8.         int width = bmSrc.getWidth();  
  9.         int height = bmSrc.getHeight();  
  10.         // 创建目标灰度图像  
  11.         Bitmap bmpGray = null;  
  12.         bmpGray = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);  
  13.         // 创建画布  
  14.         Canvas c = new Canvas(bmpGray);  
  15.         Paint paint = new Paint();  
  16.         ColorMatrix cm = new ColorMatrix();  
  17.         cm.setSaturation(0);  
  18.         ColorMatrixColorFilter f = new ColorMatrixColorFilter(cm);  
  19.         paint.setColorFilter(f);  
  20.         c.drawBitmap(bmSrc, 00, paint);  
  21.         return bmpGray;  
  22.     }  

3、线性灰度化

[java] view plain copy
  1. /** 
  2.      * 图片线性灰度处理 
  3.      *  
  4.      * @param image 
  5.      * */  
  6.     public Bitmap lineGrey(Bitmap image) {  
  7.         // 得到图像的宽度和长度  
  8.         int width = image.getWidth();  
  9.         int height = image.getHeight();  
  10.         // 创建线性拉升灰度图像  
  11.         Bitmap linegray = null;  
  12.         linegray = image.copy(Config.ARGB_8888, true);  
  13.         // 依次循环对图像的像素进行处理  
  14.         for (int i = 0; i < width; i++) {  
  15.             for (int j = 0; j < height; j++) {  
  16.                 // 得到每点的像素值  
  17.                 int col = image.getPixel(i, j);  
  18.                 int alpha = col & 0xFF000000;  
  19.                 int red = (col & 0x00FF0000) >> 16;  
  20.                 int green = (col & 0x0000FF00) >> 8;  
  21.                 int blue = (col & 0x000000FF);  
  22.                 // 增加了图像的亮度  
  23.                 red = (int) (1.1 * red + 30);  
  24.                 green = (int) (1.1 * green + 30);  
  25.                 blue = (int) (1.1 * blue + 30);  
  26.                 // 对图像像素越界进行处理  
  27.                 if (red >= 255) {  
  28.                     red = 255;  
  29.                 }  
  30.   
  31.                 if (green >= 255) {  
  32.                     green = 255;  
  33.                 }  
  34.   
  35.                 if (blue >= 255) {  
  36.                     blue = 255;  
  37.                 }  
  38.                 // 新的ARGB  
  39.                 int newColor = alpha | (red << 16) | (green << 8) | blue;  
  40.                 // 设置新图像的RGB值  
  41.                 linegray.setPixel(i, j, newColor);  
  42.             }  
  43.         }  
  44.         return linegray;  
  45.     }  

4、图片二值化

[java] view plain copy
  1. /** 
  2.      * 图像二值化处理 
  3.      *  
  4.      * @param graymap 
  5.      * */  
  6.     public Bitmap gray2Binary(Bitmap graymap) {  
  7.         // 得到图形的宽度和长度  
  8.         int width = graymap.getWidth();  
  9.         int height = graymap.getHeight();  
  10.         // 创建二值化图像  
  11.         Bitmap binarymap = null;  
  12.         binarymap = graymap.copy(Config.ARGB_8888, true);  
  13.         // 依次循环,对图像的像素进行处理  
  14.         for (int i = 0; i < width; i++) {  
  15.             for (int j = 0; j < height; j++) {  
  16.                 // 得到当前像素的值  
  17.                 int col = binarymap.getPixel(i, j);  
  18.                 // 得到alpha通道的值  
  19.                 int alpha = col & 0xFF000000;  
  20.                 // 得到图像的像素RGB的值  
  21.                 int red = (col & 0x00FF0000) >> 16;  
  22.                 int green = (col & 0x0000FF00) >> 8;  
  23.                 int blue = (col & 0x000000FF);  
  24.                 // 用公式X = 0.3×R+0.59×G+0.11×B计算出X代替原来的RGB  
  25.                 int gray = (int) ((float) red * 0.3 + (float) green * 0.59 + (float) blue * 0.11);  
  26.                 // 对图像进行二值化处理  
  27.                 if (gray <= 95) {  
  28.                     gray = 0;  
  29.                 } else {  
  30.                     gray = 255;  
  31.                 }  
  32.                 // 新的ARGB  
  33.                 int newColor = alpha | (gray << 16) | (gray << 8) | gray;  
  34.                 // 设置新图像的当前像素值  
  35.                 binarymap.setPixel(i, j, newColor);  
  36.             }  
  37.         }  
  38.         return binarymap;  
  39.     }  

5、高斯模糊

[java] view plain copy
  1. /** 
  2.      * 高斯模糊 
  3.      *  
  4.      * @param bmp 
  5.      * @return 
  6.      */  
  7.     public static Bitmap convertToBlur(Bitmap bmp) {  
  8.         // 高斯矩阵  
  9.         int[] gauss = new int[] { 121242121 };  
  10.         int width = bmp.getWidth();  
  11.         int height = bmp.getHeight();  
  12.         Bitmap newBmp = Bitmap.createBitmap(width, height,  
  13.                 Bitmap.Config.RGB_565);  
  14.         int pixR = 0;  
  15.         int pixG = 0;  
  16.         int pixB = 0;  
  17.         int pixColor = 0;  
  18.         int newR = 0;  
  19.         int newG = 0;  
  20.         int newB = 0;  
  21.         int delta = 16// 值越小图片会越亮,越大则越暗  
  22.         int idx = 0;  
  23.         int[] pixels = new int[width * height];  
  24.         bmp.getPixels(pixels, 0, width, 00, width, height);  
  25.         for (int i = 1, length = height - 1; i < length; i++) {  
  26.             for (int k = 1, len = width - 1; k < len; k++) {  
  27.                 idx = 0;  
  28.                 for (int m = -1; m <= 1; m++) {  
  29.                     for (int n = -1; n <= 1; n++) {  
  30.                         pixColor = pixels[(i + m) * width + k + n];  
  31.                         pixR = Color.red(pixColor);  
  32.                         pixG = Color.green(pixColor);  
  33.                         pixB = Color.blue(pixColor);  
  34.                         newR = newR + pixR * gauss[idx];  
  35.                         newG = newG + pixG * gauss[idx];  
  36.                         newB = newB + pixB * gauss[idx];  
  37.                         idx++;  
  38.                     }  
  39.                 }  
  40.                 newR /= delta;  
  41.                 newG /= delta;  
  42.                 newB /= delta;  
  43.                 newR = Math.min(255, Math.max(0, newR));  
  44.                 newG = Math.min(255, Math.max(0, newG));  
  45.                 newB = Math.min(255, Math.max(0, newB));  
  46.                 pixels[i * width + k] = Color.argb(255, newR, newG, newB);  
  47.                 newR = 0;  
  48.                 newG = 0;  
  49.                 newB = 0;  
  50.             }  
  51.         }  
  52.         newBmp.setPixels(pixels, 0, width, 00, width, height);  
  53.         return newBmp;  
  54.     }  

6、素描效果

[java] view plain copy
  1. /** 
  2.      * 素描效果 
  3.      *  
  4.      * @param bmp 
  5.      * @return 
  6.      */  
  7.     public static Bitmap convertToSketch(Bitmap bmp) {  
  8.         int pos, row, col, clr;  
  9.         int width = bmp.getWidth();  
  10.         int height = bmp.getHeight();  
  11.         int[] pixSrc = new int[width * height];  
  12.         int[] pixNvt = new int[width * height];  
  13.         // 先对图象的像素处理成灰度颜色后再取反  
  14.         bmp.getPixels(pixSrc, 0, width, 00, width, height);  
  15.         for (row = 0; row < height; row++) {  
  16.             for (col = 0; col < width; col++) {  
  17.                 pos = row * width + col;  
  18.                 pixSrc[pos] = (Color.red(pixSrc[pos])  
  19.                         + Color.green(pixSrc[pos]) + Color.blue(pixSrc[pos])) / 3;  
  20.                 pixNvt[pos] = 255 - pixSrc[pos];  
  21.             }  
  22.         }  
  23.         // 对取反的像素进行高斯模糊, 强度可以设置,暂定为5.0  
  24.         gaussGray(pixNvt, 5.05.0, width, height);  
  25.         // 灰度颜色和模糊后像素进行差值运算  
  26.         for (row = 0; row < height; row++) {  
  27.             for (col = 0; col < width; col++) {  
  28.                 pos = row * width + col;  
  29.                 clr = pixSrc[pos] << 8;  
  30.                 clr /= 256 - pixNvt[pos];  
  31.                 clr = Math.min(clr, 255);  
  32.                 pixSrc[pos] = Color.rgb(clr, clr, clr);  
  33.             }  
  34.         }  
  35.         bmp.setPixels(pixSrc, 0, width, 00, width, height);  
  36.         return bmp;  
  37.     }  
  38.     private static int gaussGray(int[] psrc, double horz, double vert,  
  39.             int width, int height) {  
  40.         int[] dst, src;  
  41.         double[] n_p, n_m, d_p, d_m, bd_p, bd_m;  
  42.         double[] val_p, val_m;  
  43.         int i, j, t, k, row, col, terms;  
  44.         int[] initial_p, initial_m;  
  45.         double std_dev;  
  46.         int row_stride = width;  
  47.         int max_len = Math.max(width, height);  
  48.         int sp_p_idx, sp_m_idx, vp_idx, vm_idx;  
  49.         val_p = new double[max_len];  
  50.         val_m = new double[max_len];  
  51.         n_p = new double[5];  
  52.         n_m = new double[5];  
  53.         d_p = new double[5];  
  54.         d_m = new double[5];  
  55.         bd_p = new double[5];  
  56.         bd_m = new double[5];  
  57.         src = new int[max_len];  
  58.         dst = new int[max_len];  
  59.         initial_p = new int[4];  
  60.         initial_m = new int[4];  
  61.         // 垂直方向  
  62.         if (vert > 0.0) {  
  63.             vert = Math.abs(vert) + 1.0;  
  64.             std_dev = Math.sqrt(-(vert * vert) / (2 * Math.log(1.0 / 255.0)));  
  65.             // 初试化常量  
  66.             findConstants(n_p, n_m, d_p, d_m, bd_p, bd_m, std_dev);  
  67.             for (col = 0; col < width; col++) {  
  68.                 for (k = 0; k < max_len; k++) {  
  69.                     val_m[k] = val_p[k] = 0;  
  70.                 }  
  71.                 for (t = 0; t < height; t++) {  
  72.                     src[t] = psrc[t * row_stride + col];  
  73.                 }  
  74.                 sp_p_idx = 0;  
  75.                 sp_m_idx = height - 1;  
  76.                 vp_idx = 0;  
  77.                 vm_idx = height - 1;  
  78.                 initial_p[0] = src[0];  
  79.                 initial_m[0] = src[height - 1];  
  80.                 for (row = 0; row < height; row++) {  
  81.                     terms = (row < 4) ? row : 4;  
  82.                     for (i = 0; i <= terms; i++) {  
  83.                         val_p[vp_idx] += n_p[i] * src[sp_p_idx - i] - d_p[i]  
  84.                                 * val_p[vp_idx - i];  
  85.                         val_m[vm_idx] += n_m[i] * src[sp_m_idx + i] - d_m[i]  
  86.                                 * val_m[vm_idx + i];  
  87.                     }  
  88.                     for (j = i; j <= 4; j++) {  
  89.                         val_p[vp_idx] += (n_p[j] - bd_p[j]) * initial_p[0];  
  90.                         val_m[vm_idx] += (n_m[j] - bd_m[j]) * initial_m[0];  
  91.                     }  
  92.                     sp_p_idx++;  
  93.                     sp_m_idx--;  
  94.                     vp_idx++;  
  95.                     vm_idx--;  
  96.                 }  
  97.                 transferGaussPixels(val_p, val_m, dst, 1, height);  
  98.                 for (t = 0; t < height; t++) {  
  99.                     psrc[t * row_stride + col] = dst[t];  
  100.                 }  
  101.             }  
  102.         }  
  103.         // 水平方向  
  104.         if (horz > 0.0) {  
  105.             horz = Math.abs(horz) + 1.0;  
  106.             if (horz != vert) {  
  107.                 std_dev = Math.sqrt(-(horz * horz)  
  108.                         / (2 * Math.log(1.0 / 255.0)));  
  109.                 // 初试化常量  
  110.                 findConstants(n_p, n_m, d_p, d_m, bd_p, bd_m, std_dev);  
  111.             }  
  112.             for (row = 0; row < height; row++) {  
  113.                 for (k = 0; k < max_len; k++) {  
  114.                     val_m[k] = val_p[k] = 0;  
  115.                 }  
  116.                 for (t = 0; t < width; t++) {  
  117.                     src[t] = psrc[row * row_stride + t];  
  118.                 }  
  119.                 sp_p_idx = 0;  
  120.                 sp_m_idx = width - 1;  
  121.                 vp_idx = 0;  
  122.                 vm_idx = width - 1;  
  123.                 initial_p[0] = src[0];  
  124.                 initial_m[0] = src[width - 1];  
  125.                 for (col = 0; col < width; col++) {  
  126.                     terms = (col < 4) ? col : 4;  
  127.                     for (i = 0; i <= terms; i++) {  
  128.                         val_p[vp_idx] += n_p[i] * src[sp_p_idx - i] - d_p[i]  
  129.                                 * val_p[vp_idx - i];  
  130.                         val_m[vm_idx] += n_m[i] * src[sp_m_idx + i] - d_m[i]  
  131.                                 * val_m[vm_idx + i];  
  132.                     }  
  133.                     for (j = i; j <= 4; j++) {  
  134.                         val_p[vp_idx] += (n_p[j] - bd_p[j]) * initial_p[0];  
  135.                         val_m[vm_idx] += (n_m[j] - bd_m[j]) * initial_m[0];  
  136.                     }  
  137.                     sp_p_idx++;  
  138.                     sp_m_idx--;  
  139.                     vp_idx++;  
  140.                     vm_idx--;  
  141.                 }  
  142.                 transferGaussPixels(val_p, val_m, dst, 1, width);  
  143.                 for (t = 0; t < width; t++) {  
  144.                     psrc[row * row_stride + t] = dst[t];  
  145.                 }  
  146.             }  
  147.         }  
  148.         return 0;  
  149.     }  
  150.     private static void transferGaussPixels(double[] src1, double[] src2,  
  151.             int[] dest, int bytes, int width) {  
  152.         int i, j, k, b;  
  153.         int bend = bytes * width;  
  154.         double sum;  
  155.         i = j = k = 0;  
  156.         for (b = 0; b < bend; b++) {  
  157.             sum = src1[i++] + src2[j++];  
  158.             if (sum > 255)  
  159.                 sum = 255;  
  160.             else if (sum < 0)  
  161.                 sum = 0;  
  162.             dest[k++] = (int) sum;  
  163.         }  
  164.     }  
  165.     private static void findConstants(double[] n_p, double[] n_m, double[] d_p,  
  166.             double[] d_m, double[] bd_p, double[] bd_m, double std_dev) {  
  167.         double div = Math.sqrt(2 * 3.141593) * std_dev;  
  168.         double x0 = -1.783 / std_dev;  
  169.         double x1 = -1.723 / std_dev;  
  170.         double x2 = 0.6318 / std_dev;  
  171.         double x3 = 1.997 / std_dev;  
  172.         double x4 = 1.6803 / div;  
  173.         double x5 = 3.735 / div;  
  174.         double x6 = -0.6803 / div;  
  175.         double x7 = -0.2598 / div;  
  176.         int i;  
  177.         n_p[0] = x4 + x6;  
  178.         n_p[1] = (Math.exp(x1)  
  179.                 * (x7 * Math.sin(x3) - (x6 + 2 * x4) * Math.cos(x3)) + Math  
  180.                 .exp(x0) * (x5 * Math.sin(x2) - (2 * x6 + x4) * Math.cos(x2)));  
  181.         n_p[2] = (2  
  182.                 * Math.exp(x0 + x1)  
  183.                 * ((x4 + x6) * Math.cos(x3) * Math.cos(x2) - x5 * Math.cos(x3)  
  184.                         * Math.sin(x2) - x7 * Math.cos(x2) * Math.sin(x3)) + x6  
  185.                 * Math.exp(2 * x0) + x4 * Math.exp(2 * x1));  
  186.         n_p[3] = (Math.exp(x1 + 2 * x0)  
  187.                 * (x7 * Math.sin(x3) - x6 * Math.cos(x3)) + Math.exp(x0 + 2  
  188.                 * x1)  
  189.                 * (x5 * Math.sin(x2) - x4 * Math.cos(x2)));  
  190.         n_p[4] = 0.0;  
  191.         d_p[0] = 0.0;  
  192.         d_p[1] = -2 * Math.exp(x1) * Math.cos(x3) - 2 * Math.exp(x0)  
  193.                 * Math.cos(x2);  
  194.         d_p[2] = 4 * Math.cos(x3) * Math.cos(x2) * Math.exp(x0 + x1)  
  195.                 + Math.exp(2 * x1) + Math.exp(2 * x0);  
  196.         d_p[3] = -2 * Math.cos(x2) * Math.exp(x0 + 2 * x1) - 2 * Math.cos(x3)  
  197.                 * Math.exp(x1 + 2 * x0);  
  198.         d_p[4] = Math.exp(2 * x0 + 2 * x1);  
  199.         for (i = 0; i <= 4; i++) {  
  200.             d_m[i] = d_p[i];  
  201.         }  
  202.         n_m[0] = 0.0;  
  203.         for (i = 1; i <= 4; i++) {  
  204.             n_m[i] = n_p[i] - d_p[i] * n_p[0];  
  205.         }  
  206.         double sum_n_p, sum_n_m, sum_d;  
  207.         double a, b;  
  208.         sum_n_p = 0.0;  
  209.         sum_n_m = 0.0;  
  210.         sum_d = 0.0;  
  211.         for (i = 0; i <= 4; i++) {  
  212.             sum_n_p += n_p[i];  
  213.             sum_n_m += n_m[i];  
  214.             sum_d += d_p[i];  
  215.         }  
  216.         a = sum_n_p / (1.0 + sum_d);  
  217.         b = sum_n_m / (1.0 + sum_d);  
  218.         for (i = 0; i <= 4; i++) {  
  219.             bd_p[i] = d_p[i] * a;  
  220.             bd_m[i] = d_m[i] * b;  
  221.         }  
  222.     }  

7、锐化

[java] view plain copy
  1. /** 
  2.      * 图片锐化(拉普拉斯变换) 
  3.      *  
  4.      * @param bmp 
  5.      * @return 
  6.      */  
  7.     public static Bitmap sharpenImageAmeliorate(Bitmap bmp) {  
  8.         // 拉普拉斯矩阵  
  9.         int[] laplacian = new int[] { -1, -1, -1, -19, -1, -1, -1, -1 };  
  10.         int width = bmp.getWidth();  
  11.         int height = bmp.getHeight();  
  12.         Bitmap bitmap = Bitmap.createBitmap(width, height,  
  13.                 Bitmap.Config.RGB_565);  
  14.         int pixR = 0;  
  15.         int pixG = 0;  
  16.         int pixB = 0;  
  17.         int pixColor = 0;  
  18.         int newR = 0;  
  19.         int newG = 0;  
  20.         int newB = 0;  
  21.         int idx = 0;  
  22.         float alpha = 0.3F;  
  23.         int[] pixels = new int[width * height];  
  24.         bmp.getPixels(pixels, 0, width, 00, width, height);  
  25.         for (int i = 1, length = height - 1; i < length; i++) {  
  26.             for (int k = 1, len = width - 1; k < len; k++) {  
  27.                 idx = 0;  
  28.                 for (int m = -1; m <= 1; m++) {  
  29.                     for (int n = -1; n <= 1; n++) {  
  30.                         pixColor = pixels[(i + n) * width + k + m];  
  31.                         pixR = Color.red(pixColor);  
  32.                         pixG = Color.green(pixColor);  
  33.                         pixB = Color.blue(pixColor);  
  34.                         newR = newR + (int) (pixR * laplacian[idx] * alpha);  
  35.                         newG = newG + (int) (pixG * laplacian[idx] * alpha);  
  36.                         newB = newB + (int) (pixB * laplacian[idx] * alpha);  
  37.                         idx++;  
  38.                     }  
  39.                 }  
  40.                 newR = Math.min(255, Math.max(0, newR));  
  41.                 newG = Math.min(255, Math.max(0, newG));  
  42.                 newB = Math.min(255, Math.max(0, newB));  
  43.                 pixels[i * width + k] = Color.argb(255, newR, newG, newB);  
  44.                 newR = 0;  
  45.                 newG = 0;  
  46.                 newB = 0;  
  47.             }  
  48.         }  
  49.         bitmap.setPixels(pixels, 0, width, 00, width, height);  
  50.         return bitmap;  
  51.     }  

8、怀旧

[java] view plain copy
  1. private Bitmap OldRemeberImage(Bitmap bmp)  
  2.     {  
  3.       /* 
  4.        * 怀旧处理算法即设置新的RGB 
  5.        * R=0.393r+0.769g+0.189b 
  6.        * G=0.349r+0.686g+0.168b 
  7.        * B=0.272r+0.534g+0.131b 
  8.        */  
  9.       int width = bmp.getWidth();  
  10.       int height = bmp.getHeight();  
  11.       Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);  
  12.       int pixColor = 0;  
  13.       int pixR = 0;  
  14.       int pixG = 0;  
  15.       int pixB = 0;  
  16.       int newR = 0;  
  17.       int newG = 0;  
  18.       int newB = 0;  
  19.       int[] pixels = new int[width * height];  
  20.       bmp.getPixels(pixels, 0, width, 00, width, height);  
  21.       for (int i = 0; i < height; i++)  
  22.       {  
  23.         for (int k = 0; k < width; k++)  
  24.         {  
  25.           pixColor = pixels[width * i + k];  
  26.           pixR = Color.red(pixColor);  
  27.           pixG = Color.green(pixColor);  
  28.           pixB = Color.blue(pixColor);  
  29.           newR = (int) (0.393 * pixR + 0.769 * pixG + 0.189 * pixB);  
  30.           newG = (int) (0.349 * pixR + 0.686 * pixG + 0.168 * pixB);  
  31.           newB = (int) (0.272 * pixR + 0.534 * pixG + 0.131 * pixB);  
  32.           int newColor = Color.argb(255, newR > 255 ? 255 : newR, newG > 255 ? 255 : newG, newB > 255 ? 255 : newB);  
  33.           pixels[width * i + k] = newColor;  
  34.         }  
  35.       }  
  36.       bitmap.setPixels(pixels, 0, width, 00, width, height);  
  37.       return bitmap;  
  38.     }  

9、浮雕

[java] view plain copy
  1. //图片浮雕处理  
  2.     //底片效果也非常简单:将当前像素点的RGB值分别与255之差后的值作为当前点的RGB  
  3.     //灰度图像:通常使用的方法是gray=0.3*pixR+0.59*pixG+0.11*pixB  
  4.     private Bitmap ReliefImage(Bitmap bmp)  
  5.     {  
  6.       /* 
  7.        * 算法原理:(前一个像素点RGB-当前像素点RGB+127)作为当前像素点RGB值 
  8.        * 在ABC中计算B点浮雕效果(RGB值在0~255) 
  9.        * B.r = C.r - B.r + 127 
  10.        * B.g = C.g - B.g + 127 
  11.        * B.b = C.b - B.b + 127 
  12.        */  
  13.       int width = bmp.getWidth();  
  14.       int height = bmp.getHeight();  
  15.       Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);  
  16.       int pixColor = 0;  
  17.       int pixR = 0;  
  18.       int pixG = 0;  
  19.       int pixB = 0;  
  20.       int newR = 0;  
  21.       int newG = 0;  
  22.       int newB = 0;  
  23.       int[] pixels = new int[width * height];  
  24.       bmp.getPixels(pixels, 0, width, 00, width, height);  
  25.       for (int i = 1; i < height-1; i++)  
  26.       {  
  27.         for (int k = 1; k < width-1; k++)  
  28.         {  
  29.           //获取前一个像素颜色  
  30.           pixColor = pixels[width * i + k];     
  31.           pixR = Color.red(pixColor);  
  32.           pixG = Color.green(pixColor);  
  33.           pixB = Color.blue(pixColor);  
  34.           //获取当前像素  
  35.           pixColor = pixels[(width * i + k) + 1];  
  36.           newR = Color.red(pixColor) - pixR +127;  
  37.           newG = Color.green(pixColor) - pixG +127;  
  38.           newB = Color.blue(pixColor) - pixB +127;  
  39.           newR = Math.min(255, Math.max(0, newR));  
  40.           newG = Math.min(255, Math.max(0, newG));  
  41.           newB = Math.min(255, Math.max(0, newB));  
  42.           pixels[width * i + k] = Color.argb(255, newR, newG, newB);  
  43.         }  
  44.       }  
  45.       bitmap.setPixels(pixels, 0, width, 00, width, height);  
  46.       return bitmap;  
  47.     }  

10、光照效果

[java] view plain copy
  1. //图片光照效果  
  2.     private Bitmap SunshineImage(Bitmap bmp)  
  3.     {  
  4.       /* 
  5.        * 算法原理:(前一个像素点RGB-当前像素点RGB+127)作为当前像素点RGB值 
  6.        * 在ABC中计算B点浮雕效果(RGB值在0~255) 
  7.        * B.r = C.r - B.r + 127 
  8.        * B.g = C.g - B.g + 127 
  9.        * B.b = C.b - B.b + 127 
  10.        * 光照中心取长宽较小值为半径,也可以自定义从左上角射过来 
  11.        */         
  12.       int width = bmp.getWidth();  
  13.       int height = bmp.getHeight();  
  14.       Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);  
  15.       int pixColor = 0;  
  16.       int pixR = 0;  
  17.       int pixG = 0;  
  18.       int pixB = 0;  
  19.       int newR = 0;  
  20.       int newG = 0;  
  21.       int newB = 0;  
  22.       //围绕圆形光照  
  23.       int centerX = width / 2;  
  24.       int centerY = height / 2;  
  25.       int radius = Math.min(centerX, centerY);  
  26.       float strength = 150F;  //光照强度100-150  
  27.       int[] pixels = new int[width * height];  
  28.       bmp.getPixels(pixels, 0, width, 00, width, height);  
  29.       for (int i = 1; i < height-1; i++)  
  30.       {  
  31.         for (int k = 1; k < width-1; k++)  
  32.         {  
  33.           //获取前一个像素颜色  
  34.           pixColor = pixels[width * i + k];     
  35.           pixR = Color.red(pixColor);  
  36.           pixG = Color.green(pixColor);  
  37.           pixB = Color.blue(pixColor);  
  38.           newR = pixR;  
  39.           newG = pixG;  
  40.           newB = pixB;  
  41.           //计算当前点到光照中心的距离,平面坐标系中两点之间的距离  
  42.           int distance = (int) (Math.pow((centerY-i), 2) + Math.pow((centerX-k), 2));  
  43.           if(distance < radius*radius)  
  44.           {  
  45.             //按照距离大小计算增强的光照值  
  46.             int result = (int)(strength*( 1.0-Math.sqrt(distance) / radius ));  
  47.             newR = pixR + result;  
  48.             newG = newG + result;  
  49.             newB = pixB + result;  
  50.           }  
  51.           newR = Math.min(255, Math.max(0, newR));  
  52.           newG = Math.min(255, Math.max(0, newG));  
  53.           newB = Math.min(255, Math.max(0, newB));  
  54.           pixels[width * i + k] = Color.argb(255, newR, newG, newB);  
  55.         }  
  56.       }  
  57.       bitmap.setPixels(pixels, 0, width, 00, width, height);  
  58.       return bitmap;  
  59.     }  

11、冰冻效果

[java] view plain copy
  1. //图片冰冻效果  
  2.     private Bitmap IceImage(Bitmap bmp)  
  3.     {  
  4.       int width = bmp.getWidth();  
  5.       int height = bmp.getHeight();  
  6.       Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);  
  7.       int pixColor = 0;  
  8.       int pixR = 0;  
  9.       int pixG = 0;  
  10.       int pixB = 0;  
  11.       int newColor = 0;  
  12.       int newR = 0;  
  13.       int newG = 0;  
  14.       int newB =0;  
  15.       int[] pixels = new int[width * height];  
  16.       bmp.getPixels(pixels, 0, width, 00, width, height);  
  17.       for (int i = 0; i < height; i++)  
  18.       {  
  19.         for (int k = 0; k < width; k++)  
  20.         {  
  21.           //获取前一个像素颜色  
  22.           pixColor = pixels[width * i + k];     
  23.           pixR = Color.red(pixColor);  
  24.           pixG = Color.green(pixColor);  
  25.           pixB = Color.blue(pixColor);  
  26.           //红色  
  27.           newColor = pixR - pixG - pixB;  
  28.           newColor = newColor * 3 / 2;  
  29.           if(newColor < 0) {  
  30.             newColor = -newColor;  
  31.           }  
  32.           if(newColor >255) {  
  33.             newColor = 255;  
  34.           }  
  35.           newR = newColor;  
  36.           //绿色  
  37.           newColor = pixG - pixB - pixR;  
  38.           newColor = newColor * 3 / 2;  
  39.           if(newColor < 0) {  
  40.             newColor = -newColor;  
  41.           }  
  42.           if(newColor >255) {  
  43.             newColor = 255;  
  44.           }  
  45.           newG = newColor;  
  46.           //蓝色  
  47.           newColor = pixB - pixG - pixR;  
  48.           newColor = newColor * 3 / 2;  
  49.           if(newColor < 0) {  
  50.             newColor = -newColor;  
  51.           }  
  52.           if(newColor >255) {  
  53.             newColor = 255;  
  54.           }  
  55.           newB = newColor;  
  56.           pixels[width * i + k] = Color.argb(255, newR, newG, newB);  
  57.         }  
  58.       }  
  59.       bitmap.setPixels(pixels, 0, width, 00, width, height);  
  60.       return bitmap;  
  61.     }  

12、直方图均值化

[java] view plain copy
  1. /* 
  2.      *直方图均衡化 
  3.      */  
  4.     public Bitmap histEqualize(Bitmap myBitmap){  
  5.         // Create new array  
  6.         int width = myBitmap.getWidth();  
  7.         int height = myBitmap.getHeight();  
  8.         int[] pix = new int[width * height];  
  9.         myBitmap.getPixels(pix, 0, width, 00, width, height);  
  10.         Matrix dataR=getDataR(pix, width, height);  
  11.         Matrix dataG=getDataG(pix, width, height);  
  12.         Matrix dataB=getDataB(pix, width, height);  
  13.         //Matrix dataGray=getDataGray(pix, width, height);  
  14.         /////////////////////////////////////////////////////////  
  15.         dataR=eachEqualize(dataR,width,height);  
  16.         dataG=eachEqualize(dataG,width,height);  
  17.         dataB=eachEqualize(dataB,width,height);  
  18.         ///////////////////////////////////////////////////////////////  
  19.         // Change bitmap to use new array  
  20.         Bitmap bitmap=makeToBitmap(dataR, dataG, dataB, width, height);  
  21.         myBitmap = null;  
  22.         pix = null;  
  23.         return bitmap;  
  24.     }  
  25.     private Matrix eachEqualize(Matrix temp,int width,int height){  
  26.         // 灰度映射表  
  27.         int bMap[]=new int[256];  
  28.         // 灰度映射表  
  29.         int lCount[]=new int[256];  
  30.         // 重置计数为0  
  31.         int i,j;  
  32.         for (i = 0; i < 256; i ++){  
  33.             // 清零  
  34.             lCount[i] = 0;  
  35.         }  
  36.         // 计算各个灰度值的计数 - 参考灰度直方图的绘制代码 (对话框类中)  
  37.         for (i = 0; i < height; i ++){  
  38.             for (j = 0; j < width; j ++){  
  39.                 lCount[(int)temp.get(i, j)]++;  // 计数加1  
  40.             }  
  41.         }  
  42.         // 计算灰度映射表  
  43.         for (i = 0; i < 256; i++){  
  44.             // 初始为0  
  45.             int Temp = 0;  
  46.             for (j = 0; j <= i ; j++){  
  47.                 Temp += lCount[j];  
  48.             }  
  49.             // 计算对应的新灰度值  
  50.             bMap[i] = (int) (Temp * 255 / height / width);  
  51.         }  
  52.         // 每行  
  53.         for (i = 0; i < height; i++){  
  54.             // 每列  
  55.             for (j = 0; j < width; j++){  
  56.                 temp.set(i, j, bMap[(int)temp.get(i,j)]);  
  57.             }  
  58.         }  
  59.         return temp;  
  60.     }  

特效处理代码源码:

[java] view plain copy
  1. package com.lzy.imageprolib.kits;  
  2.   
  3. import android.graphics.Bitmap;  
  4. import android.graphics.Canvas;  
  5. import android.graphics.Color;  
  6. import android.graphics.ColorMatrix;  
  7. import android.graphics.ColorMatrixColorFilter;  
  8. import android.graphics.LinearGradient;  
  9. import android.graphics.Matrix;  
  10. import android.graphics.Paint;  
  11. import android.graphics.PixelFormat;  
  12. import android.graphics.PorterDuff;  
  13. import android.graphics.PorterDuffXfermode;  
  14. import android.graphics.Rect;  
  15. import android.graphics.RectF;  
  16. import android.graphics.Shader;  
  17. import android.graphics.drawable.Drawable;  
  18. import android.media.ThumbnailUtils;  
  19. import android.os.Environment;  
  20. import android.text.TextUtils;  
  21.   
  22. import java.io.File;  
  23. import java.io.FileOutputStream;  
  24. import java.io.IOException;  
  25. import java.io.OutputStream;  
  26. import java.util.Random;  
  27.   
  28. /** 
  29.  * Created by luzhenyu on 2016/5/11. 
  30.  */  
  31. public class ImageProcessHelper {  
  32.   
  33.     ////////////////////////////////////////////////////////////////////  
  34.   
  35.     private ImageProcessHelper() {  
  36.   
  37.     }  
  38.   
  39.     private static class HelperTemp {  
  40.         private static ImageProcessHelper helper = new ImageProcessHelper();  
  41.     }  
  42.   
  43.     /** 
  44.      * 获取处理实例 
  45.      * Get ImageProcessHelper instance by single 
  46.      * 
  47.      * @return ImageProcessHelper 
  48.      */  
  49.     public static ImageProcessHelper getInstance() {  
  50.         return HelperTemp.helper;  
  51.     }  
  52.     ///////////////////////////////////////////////////////////////////