【Android进阶】(3)Android图像处理

1. 概念

色调/色相:物体传递的颜色

饱和度:颜色的纯度,从0(灰)到100%(饱和)来进行描写叙述

亮度/明度:颜色的相对明暗程度

2. 调整图像小Demo

创建一个工具类。用来设置图像的三种參数:

	/**
	 *
	 * @param bm
	 *            图像
	 * @param hue
	 *            色相
	 * @param saturation
	 *            饱和度
	 * @param lum
	 *            亮度
	 * @return
	 */
	public static Bitmap handleImageEffect(Bitmap bm, float hue, float saturation,
			float lum) {
		Bitmap bmp = Bitmap.createBitmap(bm.getWidth(), bm.getHeight(),
				Bitmap.Config.ARGB_8888);
		Canvas canvas = new Canvas(bmp);
		// 设置抗锯齿
		Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);

		// 调整色相
		ColorMatrix hueMatrix = new ColorMatrix();
		hueMatrix.setRotate(0, hue);
		hueMatrix.setRotate(1, hue);
		hueMatrix.setRotate(2, hue);
		// 饱和度
		ColorMatrix satMatrix = new ColorMatrix();
		satMatrix.setSaturation(saturation);
		// 设置亮度
		ColorMatrix lumMatrix = new ColorMatrix();
		lumMatrix.setScale(lum, lum, lum, 1);

		// 将三种设置融合
		ColorMatrix imageMatrix = new ColorMatrix();
		imageMatrix.postConcat(hueMatrix);
		imageMatrix.postConcat(satMatrix);
		imageMatrix.postConcat(lumMatrix);

		paint.setColorFilter(new ColorMatrixColorFilter(imageMatrix));
		canvas.drawBitmap(bm, 0, 0, paint);

		return bmp;
	}

然后我们在布局文件里创建一个ImageView和三个SeekBar用来调整參数,在Activity中实现OnSeekBarChangeListener接口:

	private ImageView mImageView;

	private SeekBar mSeekBarHue;
	private SeekBar mSeekBarSat;
	private SeekBar mSeekBarLum;

	private static int MAX_VALUE = 255; // SeekBar刻度最大值
	private static int MID_VALUE = 127; // SeekBar中间值

	private float mHue; // 色调
	private float mSat; // 饱和度
	private float mLum; // 亮度

	private Bitmap mBitmap;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_primarycolor);

		initView();
	}

	private void initView() {
		mImageView = (ImageView) findViewById(R.id.imageview);
		mSeekBarHue = (SeekBar) findViewById(R.id.seekbar_hue);
		mSeekBarSat = (SeekBar) findViewById(R.id.seekbar_sat);
		mSeekBarLum = (SeekBar) findViewById(R.id.seekbar_lum);

		// 设置SeekBar的最大值的刻度
		mSeekBarHue.setMax(MAX_VALUE);
		mSeekBarSat.setMax(MAX_VALUE);
		mSeekBarLum.setMax(MAX_VALUE);
		// 设置SeekBar初始值在中间
		mSeekBarHue.setProgress(MID_VALUE);
		mSeekBarSat.setProgress(MID_VALUE);
		mSeekBarLum.setProgress(MID_VALUE);

		mSeekBarHue.setOnSeekBarChangeListener(this);
		mSeekBarSat.setOnSeekBarChangeListener(this);
		mSeekBarLum.setOnSeekBarChangeListener(this);

		mBitmap = BitmapFactory
				.decodeResource(getResources(), R.drawable.test3);
		mImageView.setImageBitmap(mBitmap);
	}

	@Override
	public void onProgressChanged(SeekBar seekBar, int progress,
			boolean fromUser) {
		switch (seekBar.getId()) {
		case R.id.seekbar_hue:
			mHue = (progress - MID_VALUE) * 1.0F / MID_VALUE * 180;
			break;
		case R.id.seekbar_sat:
			mSat = progress * 1.0F / MID_VALUE;
			break;
		case R.id.seekbar_lum:
			mLum = progress * 1.0F / MID_VALUE;
			break;
		}
		Bitmap bmp = ImageHelper.handleImageEffect(mBitmap, mHue, mSat, mLum);
		mImageView.setImageBitmap(bmp);
	}

	@Override
	public void onStartTrackingTouch(SeekBar seekBar) {

	}

	@Override
	public void onStopTrackingTouch(SeekBar seekBar) {

	}

3. 颜色矩阵变换

原理:

新创建一个布局:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <ImageView
        android:id="@+id/imageview"
        android:layout_width="300dp"
        android:layout_height="0dp"
        android:layout_gravity="center_horizontal"
        android:layout_margin="20dp"
        android:layout_weight="2" />

    <GridLayout
        android:id="@+id/group"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="3"
        android:columnCount="5"
        android:rowCount="4" />

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:onClick="btnChange"
        android:text="Change" />

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:onClick="btnReset"
        android:text="Reset" />

</LinearLayout>

编写Acitvity:

public class ColorMatrixActivity extends Activity {

	private ImageView mImageView;
	private GridLayout mGroup;
	private Bitmap mBitmap;

	private int mEditTextWidth, mEditTextHeight;
	private EditText[] mEts = new EditText[20];
	private float[] mColorMatrix = new float[20];

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_colormatrix);
		initView();
	}

	private void initView() {
		mBitmap = BitmapFactory
				.decodeResource(getResources(), R.drawable.test1);
		mImageView = (ImageView) findViewById(R.id.imageview);
		mGroup = (GridLayout) findViewById(R.id.group);
		mImageView.setImageBitmap(mBitmap);

		mGroup.post(new Runnable() {

			@Override
			public void run() {
				// 初始化每个EditText的宽和高
				mEditTextWidth = mGroup.getWidth() / 5;
				mEditTextHeight = mGroup.getHeight() / 4;
				addEditText();
				initMatrix();
			}
		});
	}

	/**
	 * 创建每个EditText,并加入到数组中保存
	 */
	private void addEditText() {
		for (int i = 0; i < 20; i++) {
			EditText editText = new EditText(this);
			mEts[i] = editText;
			mGroup.addView(editText, mEditTextWidth, mEditTextHeight);
		}
	}

	/**
	 * 初始化矩阵
	 */
	private void initMatrix() {
		for (int i = 0; i < 20; i++) {
			if (i % 6 == 0) {
				mEts[i].setText(String.valueOf(1));
			} else {
				mEts[i].setText(String.valueOf(0));
			}
		}
	}

	/**
	 * 取得每个EditText的值,赋给数组
	 */
	private void getMatrix() {
		for (int i = 0; i < 20; i++) {
			mColorMatrix[i] = Float.valueOf(mEts[i].getText().toString());
		}
	}

	/**
	 * 将新的颜色矩阵设置到画布上
	 */
	private void setImageMatrix() {
		Bitmap bitmap = Bitmap.createBitmap(mBitmap.getWidth(),
				mBitmap.getHeight(), Bitmap.Config.ARGB_8888);
		ColorMatrix colorMatrix = new ColorMatrix();
		colorMatrix.set(mColorMatrix);

		Canvas canvas = new Canvas(bitmap);
		Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);

		paint.setColorFilter(new ColorMatrixColorFilter(colorMatrix));
		canvas.drawBitmap(mBitmap, 0, 0, paint);
		mImageView.setImageBitmap(bitmap);
	}

	/**
	 * 运行变化颜色矩阵
	 *
	 * @param v
	 */
	public void btnChange(View v) {
		getMatrix();
		setImageMatrix();
	}

	public void btnReset(View v) {
		initMatrix();
		getMatrix();
		setImageMatrix();
	}

}

4. 像素点分析

底片效果算法:

newR = 255 - oldR;

newG = 255 - oldG;

newB = 255 - oldB;

老照片效果:

newR = (int) (0.393 * oldR + 0.769 * oldG + 0.189 * oldB);

newG =
(int) (0.349 * oldR + 0.686 * oldG + 0.168 * oldB);

newB =
(int) (0.272 * oldR + 0534 * oldG + 0.131* oldB);

浮雕效果:

有ABC三点。求B点浮雕效果:

B.R = C.R - B.R + 127;

B.G = C.G - B.G + 127;

B.B = C.B - B.b + 127;

扩充ImageHelper工具类,编写转换成底片效果的方法:

	/**
	 * 将图片处理成底片效果
	 *
	 * @param bm
	 * @return
	 */
	public static Bitmap handlerImageNegative(Bitmap bm) {
		int width = bm.getWidth();
		int height = bm.getHeight();
		// 使用宽乘以高的数组来保存全部的像素点
		int[] oldPx = new int[width * height];
		int[] newPx = new int[width * height];
		int color;
		int r, g, b, a; // 保存颜色中取出的分量

		Bitmap bmp = Bitmap
				.createBitmap(width, height, Bitmap.Config.ARGB_8888);
		bm.getPixels(oldPx, 0, width, 0, 0, width, height);

		for (int i = 0; i < width * height; i++) {
			color = oldPx[i];
			// 取出每个分量
			r = Color.red(color);
			g = Color.green(color);
			b = Color.blue(color);
			a = Color.alpha(color);

			r = 255 - r;
			g = 255 - g;
			b = 255 - b;

			if (r > 255) {
				r = 255;
			} else if (r < 0) {
				r = 0;
			}
			if (g > 255) {
				g = 255;
			} else if (g < 0) {
				g = 0;
			}
			if (b > 255) {
				b = 255;
			} else if (b < 0) {
				b = 0;
			}
			newPx[i] = Color.argb(a, r, g, b);
		}
		bmp.setPixels(newPx, 0, width, 0, 0, width, height);
		return bmp;
	}

在Activity中写对应代码:

		mImageView2.setImageBitmap(ImageHelper.handlerImageNegative(bitmap));

照片怀旧效果的处理:

	/**
	 * 将图片处理成怀旧效果
	 *
	 * @param bm
	 * @return
	 */
	public static Bitmap handlerImageOldPhoto(Bitmap bm) {
		int width = bm.getWidth();
		int height = bm.getHeight();
		// 使用宽乘以高的数组来保存全部的像素点
		int[] oldPx = new int[width * height];
		int[] newPx = new int[width * height];
		int color;
		int r, g, b, a; // 保存颜色中取出的分量

		Bitmap bmp = Bitmap
				.createBitmap(width, height, Bitmap.Config.ARGB_8888);
		bm.getPixels(oldPx, 0, width, 0, 0, width, height);

		for (int i = 0; i < width * height; i++) {
			color = oldPx[i];
			// 取出每个分量
			r = Color.red(color);
			g = Color.green(color);
			b = Color.blue(color);
			a = Color.alpha(color);

			r = (int) (0.393 * r + 0.769 * g + 0.189 * b);
			g = (int) (0.349 * r + 0.686 * g + 0.168 * b);
			b = (int) (0.272 * r + 0534 * g + 0.131 * b);

			if (r > 255) {
				r = 255;
			}
			if (g > 255) {
				g = 255;
			}
			if (b > 255) {
				b = 255;
			}
			newPx[i] = Color.argb(a, r, g, b);
		}
		bmp.setPixels(newPx, 0, width, 0, 0, width, height);
		return bmp;
	}

照片浮雕效果的处理:

	/**
	 * 将图片处理成浮雕效果
	 *
	 * @param bm
	 * @return
	 */
	public static Bitmap handlerImageRilievo(Bitmap bm) {
		int width = bm.getWidth();
		int height = bm.getHeight();
		// 使用宽乘以高的数组来保存全部的像素点
		int[] oldPx = new int[width * height];
		int[] newPx = new int[width * height];
		int color;
		int r, g, b, a; // 保存颜色中取出的分量
		int r1, g1, b1; // 保存颜色中取出的分量
		int colorBefore; // 保存之前的像素值

		Bitmap bmp = Bitmap
				.createBitmap(width, height, Bitmap.Config.ARGB_8888);
		bm.getPixels(oldPx, 0, width, 0, 0, width, height);

		for (int i = 1; i < width * height; i++) {
			colorBefore = oldPx[i - 1];
			r = Color.red(colorBefore);
			g = Color.green(colorBefore);
			b = Color.blue(colorBefore);
			a = Color.alpha(colorBefore);

			color = oldPx[i];
			// 取出每个分量
			r1 = Color.red(color);
			g1 = Color.green(color);
			b1 = Color.blue(color);

			r = r - r1 + 127;
			g = g - g1 + 127;
			b = b - b1 + 127;

			if (r > 255) {
				r = 255;
			}
			if (g > 255) {
				g = 255;
			}
			if (b > 255) {
				b = 255;
			}
			newPx[i] = Color.argb(a, r, g, b);
		}
		bmp.setPixels(newPx, 0, width, 0, 0, width, height);
		return bmp;
	}

源代码下载

时间: 2024-10-13 11:32:06

【Android进阶】(3)Android图像处理的相关文章

【Android进阶】Android面试题目整理与讲解

这一篇文章专门整理一下研究过的Android面试题,内容会随着学习不断的增加,如果答案有错误,希望大家可以指正 1.简述Activity的生命周期 当Activity开始启动的时候,首先调用onCreate(),onStart(),onResume()方法,此时Activity对用户来说,是可见的状态 当Activity从可见状态变为被Dialog遮挡的状态的时候,会调用onPause()方法,此时的Activity对用户可见,但是不能相 应用户的点击事件 当Activity从可见状态变为被其他

【Android进阶】Android面试题目整理与讲解(二)

今天真机调试的时候莫名其妙遇到了这样的一个问题: This product type must be built using a provisioning profile, however no provisioning profile matching both the identity "iPhone Developer" and the bundle identifier..... 具体如下图所示: 十分蛋疼, 发现不管是从网上下的demo, 还是自己的过程.凡事真机测试的时候都

【Android进阶】Android面试题目整理与讲解(一)

这一篇文章专门整理一下研究过的Android面试题,内容会随着学习不断的增加,如果答案有错误,希望大家可以指正 1.简述Activity的生命周期 当Activity开始启动的时候,首先调用onCreate(),onStart(),onResume()方法,此时Activity对用户来说,是可见的状态 当Activity从可见状态变为被Dialog遮挡的状态的时候,会调用onPause()方法,此时的Activity对用户可见,但是不能相 应用户的点击事件 当Activity从可见状态变为被其他

[Android进阶]Android性能优化

Android性能优化 合理管理内存 节制的使用Service 如果应用程序需要使用Service来执行后台任务的话,只有当任务正在执行的时候才应该让Service运行起来.当启动一个Service时,系统会倾向于将这个Service所依赖的进程进行保留,系统可以在LRUcache当中缓存的进程数量也会减少,导致切换程序的时候耗费更多性能.我们可以使用IntentService,当后台任务执行结束后会自动停止,避免了Service的内存泄漏. 当界面不可见时释放内存 当用户打开了另外一个程序,我

Android进阶之android应用的SDK版本之间的切换

选中android工程,右键/属性,如下进行选择即可: 或者在工程属性文件中直接修改编译的SDK版本:

android进阶之android应用安装

android应用安装分为如下几步: 1.把apk文件拷贝到android系统/data/app/xxx.apk 2.在data/data目录下创建一个已当前应用包名一致的文件夹.(应用运行的数据均保存在该目录下) 安装完成. 卸载则相反. 在system目录下有类似windows的注册表.

【Android 进阶】Android Home 键监听

Android Home键监听 Android 普通键值可以直接在dispatchKeyEvent()中处理,但Home键,比较特殊,需要单独监听其广播,且必须为动态广播,其静态广播无效: 需求:Home键,设置 Kill 自己,但设置中有多个Activity,在每个Activiy 中年监听Home键广播不现实,必须把监听广播抽取出来在同一个类中实现,考虑到BaseActivity: public class BaseActivity extends Activity { private Hom

Android进阶 三 android httpClient 支持HTTPS的访问方式

项目中Android https请求地址遇到了这个异常(无终端认证): javax.net.ssl.SSLPeerUnverifiedException: No peer certificate 是SSL协议中没有终端认证. 没有遇到过的问题,于是无奈的去找度娘.......,各种问题,各种纠结...... 看了不少大神的博客后得到的解决方案如下: <span style="font-family:Times New Roman;font-size:14px;">/** *

我的Android进阶之旅------&gt;Java字符串格式化方法String.format()格式化float型时小数点变成逗号问题

今天接到一个波兰的客户说有个APP在英文状态下一切运行正常,但是当系统语言切换到波兰语言的时候,程序奔溃了.好吧,又是我来维护. 好吧,先把系统语言切换到波兰语,切换到波兰语的方法查看文章 我的Android进阶之旅------>Android[设置]-[语言和输入法]-[语言]列表中找到相应语言所对应的列表项 地址:http://blog.csdn.net/ouyang_peng/article/details/50209789 ================================