ColorMatrix色彩变换
- 对于色彩的存储,Bitmap类使用一个32位的数值来保存,红,绿,蓝以及透明度各占8位,每个色彩分量的取值范围是0~255,透明度为0表示完全透明,为255时色彩完全可见
色彩矩阵的表示:
- 由于一个色彩信息包含R、G、B、Alpha信息,所以,必须使用一个四阶色彩变幻矩阵来修改色彩的每一个分量,对于色彩矩阵来说色彩顺序是R、G、B、A
- 如果想要原有的R色上增加一些分量,那么就要在四阶矩阵上在加一阶来表示平移变换,使用四阶色彩 变换矩阵来修改颜色,只能对色彩 的每个分量值进行乘(除)运算,如果要对这些分量值进行加减法运算(平移变换),则只能通过五阶矩阵来完成。
Android中的色彩变换矩阵
- 在Android中,色彩变换矩阵的表示形式也是五阶,Android中的色彩变换矩阵是使用ColorMatri类来表示的,使用ColorMatrix类的方法如下:
ColorMatrix colormatrix = new ColorMatrix(new float[]{
1, 0, 0, 0, 0,
0, 1, 0, 0, 0,
0, 0, 1, 0, 0,
0, 0, 0, 0.5, 0,
});
paint.setCoorFilter(new ColormatrixColorFilter(colorMatrix));
eg:
public class MyMatrixColorView extends View {
private Paint paint;
private Bitmap bitmap;
public MyMatrixColorView(Context context, AttributeSet attrs) {
super(context, attrs);
paint = new Paint();
paint.setAntiAlias(true);
bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.dog);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawBitmap(bitmap, null, new Rect(0, 0, 500, 500* bitmap.getHeight() / bitmap.getWidth()), paint);
canvas.translate(510, 0);
ColorMatrix colorMatrix = new ColorMatrix(new float[]{
0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0, 1, 0, 0,
0, 0, 0, 1, 0,
});
paint.setColorFilter(new ColorMatrixColorFilter(colorMatrix));
canvas.drawBitmap(bitmap, null, new Rect(0, 0, 500, 500 * bitmap.getHeight()/bitmap.getWidth()), paint);
}
}
色彩运算的几种方式:
- 色彩的平移运算
(1) 增加色彩的饱和度- 实际上是色彩的加法运算,其实就是在色彩变换矩阵的最后一列加上某个值,这样就可以增加特定的色彩饱和度
eg:
- 实际上是色彩的加法运算,其实就是在色彩变换矩阵的最后一列加上某个值,这样就可以增加特定的色彩饱和度
ColorMatrix colorMatrix = new ColorMatrix(new float[]{
1, 0, 0, 0, 0,
0, 1, 0, 0, 50,
0, 0, 1, 0, 0,
0, 0, 0, 1, 0,
});
-
用每个像素所对应的色彩数组来乘以色彩变换矩阵,结果就是变换后的当前点的颜色值
(2)色彩反转/反相功能 -
色彩平移除增加指定色彩的饱和度以外,另一个应用就是色彩反转,也就是Photoshop中的反相功能,色彩反转就是求出每个颜色的补值来作为目标图像的对应颜色值
ColorMatrix colorMatrix = new ColorMatrix(new float[]{
-1, 0, 0, 0,255,
0, -1, 0, 0, 255,
0, 0, -1, 0, 255,
0, 0, 0, 1, 0,
});
-
色彩的缩放运算
(1)调节亮度 -
色彩的缩放运算其实就是色彩的乘法运算,将色彩变换矩阵对角线上分别代表R,G, B, A的几个之分别乘以指定的值,就是所谓的缩放运算,我们可以对某个颜色值进行放大/缩小运算,但是党对R,G,B,A同时进行放大/缩小运算时,就是对亮度的调节
-
eg:亮度调大1.2倍:
ColorMatrix colorMatrix = new ColorMatrix(new float[]{
1.2f, 0, 0, 0, 0,
0, 1.2f, 0, 0, 50,
0, 0, 1.2f, 0, 0,
0, 0, 0, 1.2f, 0,
});
(2)通道输出
- 由于再色彩变换矩阵中对角线上的数的取值范围为0~1,所以,当取0时,这个色彩就完全不显示;当R,G都取0,而独有B取1时 ,就只显示蓝色,所形成的图像也就是我通常所说的蓝色通道
(3)色彩的旋转运算
-
使用RGB三色建立立体坐标系,把RGB色彩值看作是三维空间的三个方向的坐标,可以将一个色彩值看作是三维空间中的一个点,当围绕 红色轴旋转时,是对图片进行红色色相的调节,当围绕蓝色轴旋转时,是对图片进行蓝色色相的调节,当围绕绿色轴旋转时,是对图片进行绿色色相的调节
-
色彩的投射运算
-
利用其他色彩分量的倍数来改变自己的色彩分量的值,就叫做投射运算
-
eg: 黑白照片:
ColorMatrix colorMatrix = new ColorMatrix(new float[]{
0.213f, 0.715f, 0.072f, 0, 0,
0.213f, 0.715f, 0.072f, 0, 0,
0.213f, 0.715f, 0.072f, 0, 0,
0, 0, 0, 1, 0,
});
-
去色原理:只要把R,G,B三通道的色彩信息设置成一样,即R=G=B,图像就编程了灰色,并且为了保证图像亮度不变,同一个通道中的R+G+B = 1
-
0.213, 0.715, 0.072三个数字的来历:在作用域人眼的光纤中,彩色光要明显强于无色光,如果对一张图像按照RGB平分给图像去色,人眼会明显感觉图像变暗了,另外在彩色图像中能够识别的一些细节也可能丢失
-
eg: 色彩反差:(红绿反差)
ColorMatrix colorMatrix = new ColorMatrix(new float[]{
0, 1, 0, 0, 0,
1, 0, 0, 0, 0,
0, 0, 1, 0, 0,
0, 0, 0, 1, 0,
});
- 红绿反差的关键就是第一行利用绿色来代替 红色,第二行利用红色来代替绿色
- eg: 照片做旧:
ColorMatrix colorMatrix = new ColorMatrix(new float[]{
1/2f, 1/2f, 1/2f, 0, 0,
1/3f, 1/3f, 1/3f, 0, 0,
1/4f, 1/4f, 1/4f, 0, 0,
0,0,0,1,0,
});
[外链图片转存失败(img-6KfSQcJl-1562243584764)(en-resource://database/5280:0)]
ColorMatrix函数
- 在Android中,ColorMatrix自带一些函数,用来帮助我们完成调整饱和度、色彩旋转等操作
ColorMatrix有三个构造函数:
ColorMatrix()
ColorMatrix(float[] src)
ColorMatrix(ColorMatrix src)//利用一个ColorMatrix实例来复制一个一样的ColorMatrix对象
设置和重置函数
public void set(ColorMatrix src);
public void set(float[] src)
public void reset()
//重置后,对应的数组如下:
[ 1 0 0 0 0 -red vector
0 1 0 0 0 -green vector
0 0 1 0 0 -blue vector
0 0 0 1 0] -alpha vector
setSaturation()函数–设置饱和度
- 上面讲述了如何提高一个颜色分量的饱和度,这个函数是用来提高整体的色彩饱和度的
//同时增强R,G,B的色彩饱和度
//sat 表示把当前色彩饱和度放大的倍数,取值为0时完全无色彩(灰度图像);当取值为1时,色彩不进行变动,当取值大于1时,显示色彩过渡饱和
public void setSaturation(float sat)
eg:
private ImageView imageView;
private SeekBar seekBar;
private Bitmap bitmap;
private Bitmap tempBitmap;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_matrix);
imageView = (ImageView) findViewById(R.id.image_bitmap);
seekBar = (SeekBar)findViewById(R.id.seekbar);
bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.dog);
tempBitmap = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888);
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
Bitmap bitmap1 = handleColorMatrixBmp(progress);
imageView.setImageBitmap(bitmap1);
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
}
private Bitmap handleColorMatrixBmp(int progress) {
//创建一个相同尺寸的可变长的位图去,用于绘制调色后的图片
Canvas canvas = new Canvas(tempBitmap);
Paint paint = new Paint();
ColorMatrix colorMatrix = new ColorMatrix();
colorMatrix.setSaturation(progress);
paint.setColorFilter(new ColorMatrixColorFilter(colorMatrix));
canvas.drawBitmap(bitmap, 0, 0, paint);
return tempBitmap;
}
setScale()函数----色彩缩放
//四个参数分别对应R,G,B, A颜色值的缩放倍数
public void setScale(float rScale, float gScale, float bScale, float aScale)
eg:仅将 绿色放大1.3倍
canvas.drawBitmap(bitmap, null, new Rect(0, 0,500,500 * bitmap.getHeight() / bitmap.getWidth()), paint);
canvas.save();
canvas.translate(510, 0);
//生成色彩变换矩阵
ColorMatrix colorMatrix = new ColorMatrix();
colorMatrix.setScale(1, 1.3f, 1,1);
paint.setColorFilter(new ColorMatrixColorFilter(colorMatrix));
canvas.drawBitmap(bitmap, null, new Rect(0, 0, 500, 500 * bitmap.getHeight()/ bitmap.getWidth()), paint);
[外链图片转存失败(img-LOl3Zu3U-1562243584765)(en-resource://database/5282:1)]
setRotate()函数----色彩旋转
//将旋转围绕某一个颜色轴进行
axis=0 围绕红色轴旋转
axis=1围绕绿色轴进行旋转
axis=2围绕蓝色轴进行旋转
public void setRotate(int axis, float degrees);
ColorMatrix相乘
//乘法规则为matA x matB,然后将结果作为当前ColorMatrix的值
public void setConcat(ColorMatrix matA, ColorMatrix matB)
//假设当前矩阵为A,那么preConcat()的含义就是将当前矩阵A乘以prematrix
public void peConcat(ColorMatrix prematrix)
//postmatrix矩阵乘以当前矩阵A
public void postConcat(ColorMatrix postmatrix)