【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; }