1.RGBA模型分析
R- red
G- green
B- blue
A- alpha
关于RGBA模型,有三个比较重要的属性概念必须要清楚:
android中关于这三个属性有不同的方法去改变:
色调:
ColorMatrix cMatrix = new ColorMatrix();
cMatrix.setRotate(0/1/2, xxx); --> 0代表R,1代表G,2代表B, xxx是具体的值
饱和度:
ColorMatrix cMatrix = new ColorMatrix();
cMatrix.setSaturation(xxx);
亮度:
ColorMatrix
cMatrix = new ColorMatrix();
cMatrix.setScale(xx,xx,xx,1);
2. 项目分析
一.创建一个处理图像的工具类:
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Paint;
public class ImageHelper {
/**
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Paint;
public class ImageHelper {
/**
* 色彩,饱和度,亮度的调整
传入的 bitmap不能修改,否则会报错,所以要先创建一个bitmap
*/
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 saturationMatrix = new ColorMatrix();
saturationMatrix.setSaturation(saturation);
ColorMatrix lumMatrix = new ColorMatrix();
lumMatrix.setScale(lum, lum, lum, 1);
// 将不同的colorMatrix糅合一起
ColorMatrix imageMatrix = new ColorMatrix();
imageMatrix.postConcat(hueMatrix);
imageMatrix.postConcat(saturationMatrix);
imageMatrix.postConcat(lumMatrix);
// 用画笔画在画布上,返回一个新的bitmap
paint.setColorFilter(new ColorMatrixColorFilter(imageMatrix));
canvas.drawBitmap(bm, 0, 0, paint);
return bmp;
}
/**
* 调整像素点 (底片效果)
*/
public static Bitmap handleImageNegative(Bitmap bm) {
int width = bm.getWidth();
int height = bm.getHeight();
int color;
int r, g, b, a;
Bitmap bmp = Bitmap.createBitmap(width, height
, Bitmap.Config.ARGB_8888);
int[] oldPx = new int[width * height];
int[] newPx = new int[width * height];
bm.getPixels(oldPx, 0, width, 0, 0, width, height); // 将图片的像素点读取到集合 oldPx中
for (int i = 0; i < width * height; i++) {
color = oldPx[i];
// 通过Color类分离出每个像素点的r g b a。
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;
}
public static Bitmap handleImagePixelsOldPhoto(Bitmap bm) {
Bitmap bmp = Bitmap.createBitmap(bm.getWidth(), bm.getHeight(),
Bitmap.Config.ARGB_8888);
int width = bm.getWidth();
int height = bm.getHeight();
int color = 0;
int r, g, b, a, r1, g1, b1;
int[] oldPx = new int[width * height];
int[] newPx = new int[width * height];
bm.getPixels(oldPx, 0, bm.getWidth(), 0, 0, width, height);
for (int i = 0; i < width * height; i++) {
color = oldPx[i];
a = Color.alpha(color);
r = Color.red(color);
g = Color.green(color);
b = Color.blue(color);
r1 = (int) (0.393 * r + 0.769 * g + 0.189 * b);
g1 = (int) (0.349 * r + 0.686 * g + 0.168 * b);
b1 = (int) (0.272 * r + 0.534 * g + 0.131 * b);
if (r1 > 255) {
r1 = 255;
}
if (g1 > 255) {
g1 = 255;
}
if (b1 > 255) {
b1 = 255;
}
newPx[i] = Color.argb(a, r1, g1, b1);
}
bmp.setPixels(newPx, 0, width, 0, 0, width, height);
return bmp;
}
public static Bitmap handleImagePixelsRelief(Bitmap bm) {
Bitmap bmp = Bitmap.createBitmap(bm.getWidth(), bm.getHeight(),
Bitmap.Config.ARGB_8888);
int width = bm.getWidth();
int height = bm.getHeight();
int color = 0, colorBefore = 0;
int a, r, g, b;
int r1, g1, b1;
int[] oldPx = new int[width * height];
int[] newPx = new int[width * height];
bm.getPixels(oldPx, 0, bm.getWidth(), 0, 0, width, height);
for (int i = 1; i < width * height; i++) {
colorBefore = oldPx[i - 1];
a = Color.alpha(colorBefore);
r = Color.red(colorBefore);
g = Color.green(colorBefore);
b = Color.blue(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;
}
}
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;
}
/**
* 调整像素点 (怀旧效果)
*/
public static Bitmap handleImagePixelsOldPhoto(Bitmap bm) {
Bitmap bmp = Bitmap.createBitmap(bm.getWidth(), bm.getHeight(),
Bitmap.Config.ARGB_8888);
int width = bm.getWidth();
int height = bm.getHeight();
int color = 0;
int r, g, b, a, r1, g1, b1;
int[] oldPx = new int[width * height];
int[] newPx = new int[width * height];
bm.getPixels(oldPx, 0, bm.getWidth(), 0, 0, width, height);
for (int i = 0; i < width * height; i++) {
color = oldPx[i];
a = Color.alpha(color);
r = Color.red(color);
g = Color.green(color);
b = Color.blue(color);
r1 = (int) (0.393 * r + 0.769 * g + 0.189 * b);
g1 = (int) (0.349 * r + 0.686 * g + 0.168 * b);
b1 = (int) (0.272 * r + 0.534 * g + 0.131 * b);
if (r1 > 255) {
r1 = 255;
}
if (g1 > 255) {
g1 = 255;
}
if (b1 > 255) {
b1 = 255;
}
newPx[i] = Color.argb(a, r1, g1, b1);
}
bmp.setPixels(newPx, 0, width, 0, 0, width, height);
return bmp;
}
/**
* 调整像素点 (浮雕效果)
*/
public static Bitmap handleImagePixelsRelief(Bitmap bm) {
Bitmap bmp = Bitmap.createBitmap(bm.getWidth(), bm.getHeight(),
Bitmap.Config.ARGB_8888);
int width = bm.getWidth();
int height = bm.getHeight();
int color = 0, colorBefore = 0;
int a, r, g, b;
int r1, g1, b1;
int[] oldPx = new int[width * height];
int[] newPx = new int[width * height];
bm.getPixels(oldPx, 0, bm.getWidth(), 0, 0, width, height);
for (int i = 1; i < width * height; i++) {
colorBefore = oldPx[i - 1];
a = Color.alpha(colorBefore);
r = Color.red(colorBefore);
g = Color.green(colorBefore);
b = Color.blue(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;
}
}
二.创建PrimaryColor 和布局文件 primary_color.xml:
primary_color.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/imageview"
android:layout_width="300dp"
android:layout_height="300dp"
android:layout_marginTop="24dp"
android:layout_marginBottom="24dp"
android:layout_centerHorizontal="true"/>
<SeekBar
android:id="@+id/seekbarHue"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/imageview"/>
<SeekBar
android:id="@+id/seekbarSaturation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/seekbarHue"/>
<SeekBar
android:id="@+id/seekbatLum"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/seekbarSaturation"/>
</RelativeLayout>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/imageview"
android:layout_width="300dp"
android:layout_height="300dp"
android:layout_marginTop="24dp"
android:layout_marginBottom="24dp"
android:layout_centerHorizontal="true"/>
<SeekBar
android:id="@+id/seekbarHue"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/imageview"/>
<SeekBar
android:id="@+id/seekbarSaturation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/seekbarHue"/>
<SeekBar
android:id="@+id/seekbatLum"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/seekbarSaturation"/>
</RelativeLayout>
PrimaryColor :
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.widget.ImageView;
import android.widget.SeekBar;
public class PrimaryColor extends Activity implements SeekBar.OnSeekBarChangeListener{
private ImageView mImageView;
private SeekBar mSeekbarhue,mSeekbarSaturation, mSeekbarLum;
private static int MAX_VALUE = 255;
private static int MID_VALUE = 127;
private float mHue,mStauration, mLum;
private Bitmap bitmap;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.primary_color);
bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.test3);
mImageView = (ImageView) findViewById(R.id.imageview);
mSeekbarhue = (SeekBar) findViewById(R.id.seekbarHue);
mSeekbarSaturation = (SeekBar) findViewById(R.id.seekbarSaturation);
mSeekbarLum = (SeekBar) findViewById(R.id.seekbatLum);
mSeekbarhue.setOnSeekBarChangeListener(this);
mSeekbarSaturation.setOnSeekBarChangeListener(this);
mSeekbarLum.setOnSeekBarChangeListener(this);
mSeekbarhue.setMax(MAX_VALUE);
mSeekbarSaturation.setMax(MAX_VALUE);
mSeekbarLum.setMax(MAX_VALUE);
mSeekbarSaturation.setMax(MAX_VALUE);
mSeekbarLum.setMax(MAX_VALUE);
mSeekbarhue.setProgress(MID_VALUE);
mSeekbarSaturation.setProgress(MID_VALUE);
mSeekbarLum.setProgress(MID_VALUE);
mImageView.setImageBitmap(bitmap);
}
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
switch (seekBar.getId()) {
case R.id.seekbarHue:
mHue = (progress - MID_VALUE) * 1.0F / MID_VALUE * 180; // 将seekbar的值转化成色值的公式
break;
case R.id.seekbarSaturation:
mStauration = progress * 1.0F / MID_VALUE;// 0~2
break;
case R.id.seekbatLum:
mLum = progress * 1.0F / MID_VALUE; // 0~2
break;
}
mImageView.setImageBitmap(ImageHelper.handleImageEffect(bitmap, mHue, mStauration, mLum));
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
}
mSeekbarSaturation.setProgress(MID_VALUE);
mSeekbarLum.setProgress(MID_VALUE);
mImageView.setImageBitmap(bitmap);
}
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
switch (seekBar.getId()) {
case R.id.seekbarHue:
mHue = (progress - MID_VALUE) * 1.0F / MID_VALUE * 180; // 将seekbar的值转化成色值的公式
break;
case R.id.seekbarSaturation:
mStauration = progress * 1.0F / MID_VALUE;// 0~2
break;
case R.id.seekbatLum:
mLum = progress * 1.0F / MID_VALUE; // 0~2
break;
}
mImageView.setImageBitmap(ImageHelper.handleImageEffect(bitmap, mHue, mStauration, mLum));
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
}
3. 通过矩阵的变化处理图像(关于这个知识点以后会更新一些更详细的内容)
创建ColorMatrix和布局文件 color_matrix.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/imageview"
android:layout_width="match_parent"
android:layout_weight="2"
android:layout_height="0dp" />
<GridLayout
android:id="@+id/group"
android:layout_width="match_parent"
android:layout_weight="3"
android:layout_height="0dp"
android:rowCount="4"
android:columnCount="5">
</GridLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Change"
android:onClick="btnChange" />
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Reset"
android:onClick="btnReset" />
</LinearLayout>
</LinearLayout>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/imageview"
android:layout_width="match_parent"
android:layout_weight="2"
android:layout_height="0dp" />
<GridLayout
android:id="@+id/group"
android:layout_width="match_parent"
android:layout_weight="3"
android:layout_height="0dp"
android:rowCount="4"
android:columnCount="5">
</GridLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Change"
android:onClick="btnChange" />
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Reset"
android:onClick="btnReset" />
</LinearLayout>
</LinearLayout>
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Paint;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.GridLayout;
import android.widget.ImageView;
public class ColorMatrix extends Activity {
private ImageView mImageView;
private GridLayout mGroup;
private Bitmap bitmap;
private int mEtWidth, mEtHeight;
private EditText[] mEts = new EditText[20];
private float[] mColorMatrix = new float[20];
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.color_matrix);
bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.test1);
mImageView = (ImageView) findViewById(R.id.imageview);
mGroup = (GridLayout) findViewById(R.id.group);
mImageView.setImageBitmap(bitmap);
// 获取控件的宽高
mGroup.post(new Runnable() {
@Override
public void run() {
mEtWidth = mGroup.getWidth() / 5;
mEtHeight = mGroup.getHeight() / 4;
addEts();
initMatrix();
}
});
}
private void getMatrix() {
for (int i = 0; i < 20; i++) {
mColorMatrix[i] = Float.valueOf(mEts[i].getText().toString());
}
}
private void setImageMatrix() {
Bitmap bmp = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(),
Bitmap.Config.ARGB_8888);
android.graphics.ColorMatrix colorMatrix = new android.graphics.ColorMatrix();
colorMatrix.set(mColorMatrix);
Canvas canvas = new Canvas(bmp);
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColorFilter(new ColorMatrixColorFilter(colorMatrix));
canvas.drawBitmap(bitmap, 0, 0, paint);
mImageView.setImageBitmap(bmp);
}
public void btnChange(View view) {
getMatrix();
setImageMatrix();
}
public void btnReset(View view) {
initMatrix();
getMatrix();
setImageMatrix();
}
private void addEts() {
for (int i = 0; i < 20; i++) {
EditText editText = new EditText(ColorMatrix.this);
mEts[i] = editText;
mGroup.addView(editText, mEtWidth, mEtHeight);
}
}
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));
}
}
}
}
4. 像素点(简单来说就是 循环图片的像素点,然后对每个像素点的RGBA元素进行改变, 再生成一个新的bitmap,关键点在于不同的效果需要不同的算法,这个以后再谈。)
图像经过放大后,会呈现一个个点阵,每一个点阵就是一个像素点,通过控制像素点的颜色配比,就可以显示出不同的颜色。
方法参考 ImageHelper.
后记: 图片处理的原理其实很简单,要么是对矩阵的处理,要么是对像素点或者三原色饱和度亮度的处理, 最关键的部分就是算法,有兴趣的同学或者有需求的同学可以试着找一些好的算法试试看。