颜色矩阵
android中能够经过颜色矩阵(ColorMatrix类)方面的操做颜色,颜色矩阵是一个4X5 的矩阵(如图1.1)java
能够用来方面的修改图片中RGBA各份量的值,颜色矩阵以一维数组的方式存储以下:
[ a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t ]
他经过RGBA四个通道来直接操做对应颜色,若是会使用Photoshop就会知道有时处理图片经过控制RGBA各颜色通道来作出特殊的效果。android
这个矩阵对颜色的做用计算方式如1.3示:
矩阵的运算规则是矩阵A的一行乘以矩阵C的一列做为矩阵R的一行,编程
C矩阵是图片中包含的ARGB信息,R矩阵是用颜色矩阵应用于C以后的新的颜色份量,运算结果以下:
R' = a*R + b*G + c*B + d*A + e;
G' = f*R + g*G + h*B + i*A + j;
B' = k*R + l*G + m*B + n*A + o;
A' = p*R + q*G + r*B + s*A + t;
颜色矩阵并非看上去那么深奥,其实须要使用的参数不多,并且颇有规律第一行决定红色第二行决定绿色canvas
第三行决定蓝色,第四行决定了透明度,第五列是颜色的偏移量。下面是一个实际中使用的颜色矩阵。
若是把这个矩阵做用于各颜色份量的话,R=A*C,计算后会发现,各个颜色份量实际上没有任何的改变(R'=R G'=G B'=B A'=A)。
图1.5所示矩阵计算后会发现红色份量增长100,绿色份量增长100,小程序
这样的效果就是图片偏黄,由于红色和绿色混合后获得黄色,黄色增长了100,图片固然就偏黄了。
改变各颜色份量不只能够经过修改第5列的颜色偏移量也可如上面矩阵所示将对应的颜色值乘以一个倍数,直接放大。数组
上图1.6是将绿色份量乘以2变为原来的2倍。相信读者至此已经明白了如何经过颜色矩阵来改变各颜色份量。ide
下面编写一段代码来,经过调整颜色矩阵来得到不一样的颜色效果,JavaCode以下:函数
[java] view plaincopy学习
CMatrix类: spa
public class CMatrix extends Activity {
private Button change;
private EditText [] et=new EditText[20];
private float []carray=new float[20];
private MyImage sv;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
change=(Button)findViewById(R.id.set);
sv=(MyImage)findViewById(R.id.MyImage);
for(int i=0;i<20;i++){
et[i]=(EditText)findViewById(R.id.indexa+i);
carray[i]=Float.valueOf(et[i].getText().toString());
}
change.setOnClickListener(l);
}
private Button.OnClickListener l=new Button.OnClickListener(){
@Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
getValues();
sv.setValues(carray);
sv.invalidate();
}
};
public void getValues(){
for(int i=0;i<20;i++){
carray[i]=Float.valueOf(et[i].getText().toString());
}
}
}
MyImage类继承自View类:
public class MyImage extends View {
private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private Bitmap mBitmap;
private float [] array=new float[20];
private float mAngle;
public MyImage(Context context,AttributeSet attrs) {
super(context,attrs);
mBitmap = BitmapFactory.decodeResource(context.getResources(),
R.drawable.test);
invalidate();
}
public void setValues(float [] a){
for(int i=0;i<20;i++){
array[i]=a[i];
}
}
@Override protected void onDraw(Canvas canvas) {
Paint paint = mPaint;
paint.setColorFilter(null);
canvas.drawBitmap(mBitmap, 0, 0, paint);
ColorMatrix cm = new ColorMatrix();
//设置颜色矩阵
cm.set(array);
//颜色滤镜,将颜色矩阵应用于图片
paint.setColorFilter(new ColorMatrixColorFilter(cm));
//绘图
canvas.drawBitmap(mBitmap, 0, 0, paint);
Log.i("CMatrix", "--------->onDraw");
}
}
[java] view plaincopy
CMatrix类主要负责接收颜色矩阵的设置和重绘,没有要说的。MyImage类中进行绘图工做,首先设置颜色矩阵cm.set(..)从一维数组中读取数据20个数据给颜色矩阵赋值,paint.setColorFilter(..)设置颜色滤镜,而后绘图,效果就出来了(这个过程和PS差很少)以下:
看到这里,相信你们对颜色矩阵的做用已经有了一个直观的感觉,如今也能够尝试作一个照片特效的软件。
可是各类效果并不能让用户手动调节颜色矩阵,这里须要计算公式,因为本人并非作图形软件的也不能提供,能够参考这个连接:
http://www.adobe.com/devnet/flash/articles/matrix_transformations/ColorMatrixDemo.swf
坐标变换矩阵
坐标变换矩阵是一个3*3的矩阵如图2.1,用来对图形进行坐标变化,将原来的坐标点转移到新的坐标点,
由于一个图片是有点阵和每一点上的颜色信息组成的,因此对坐标的变换,就是对每一点进行搬移造成新的图片。
具体的说图形的放大缩小,移动,旋转,透视,扭曲这些效果均可以用此矩阵来完成。
这个矩阵的做用是对坐标x,y进行变换计算结果以下:
x'=a*x+b*y+c
y'=d*x+e*y+f
一般状况下g=h=0,这样使1=0*x+0*y+1恒成立。和颜色矩阵同样,坐标变换矩阵真正使用的参数不多也颇有规律。
上图就是一个坐标变换矩阵的简单例子,计算后发现x'=x+50,y'=y+50.
可见图片的每一点都在x和y方向上平移到了(50,50)点处,这种效果就是平移效果,将图片转移到了(50,50)处。
计算上面得矩阵x'=2*x,y‘=2*y.通过颜色矩阵和上面转移效果学习,相信读者能够明白这个矩阵的做用了,这个矩阵对图片进行了放大,具体的说是放大了二倍。
下面将介绍几种经常使用的变换矩阵:
1. 旋转
绕原点逆时针旋转θ度角的变换公式是 x' = xcosθ − ysinθ 与 y。' = xsinθ + ycosθ
2. 缩放
变换后长宽分别放大x'=scale*x;y'=scale*y.
3. 切变
4. 反射
( , )单位向量
5. 正投影
( , )单位向量
上面的各类效果也能够叠加在一块儿,既矩阵的组合变换,能够用矩阵乘法实现之,如:R=B(A*C)=(B*A)C,注意一点就是B*A和A*B通常是不等的。
下面将编一个小程序,经过控制坐标变换矩阵来达到控制图形的目的,JavaCode以下:
[java] view plaincopy
CooMatrix类:
public class CooMatrix extends Activity {
private Button change;
private EditText [] et=new EditText[9];
private float []carray=new float[9];
private MyImage sv;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
change=(Button)findViewById(R.id.set);
sv=(MyImage)findViewById(R.id.MyImage);
for(int i=0;i<9;i++){
et[i]=(EditText)findViewById(R.id.indexa+i);
carray[i]=Float.valueOf(et[i].getText().toString());
}
change.setOnClickListener(l);
}
private Button.OnClickListener l=new Button.OnClickListener(){
@Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
getValues();
sv.setValues(carray);
sv.invalidate();
}
};
public void getValues(){
for(int i=0;i<9;i++){
carray[i]=Float.valueOf(et[i].getText().toString());
}
}
}
MyImage类继承自View类:
public class MyImage extends View {
private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private Bitmap mBitmap;
private float [] array=new float[9];
public MyImage(Context context,AttributeSet attrs) {
super(context,attrs);
mBitmap = BitmapFactory.decodeResource(context.getResources(),
R.drawable.ic_launcher_android);
invalidate();
}
public void setValues(float [] a){
for(int i=0;i<9;i++){
array[i]=a[i];
}
}
@Override protected void onDraw(Canvas canvas) {
Paint paint = mPaint;
canvas.drawBitmap(mBitmap, 0, 0, paint);
//new 一个坐标变换矩阵
Matrix cm = new Matrix();
//为坐标变换矩阵设置响应的值
cm.setValues(array);
//按照坐标变换矩阵的描述绘图
canvas.drawBitmap(mBitmap, cm, paint);
Log.i("CMatrix", "--------->onDraw");
}
上面的代码中类CooMatrix用于接收用户输入的坐标变换矩阵参数,类MyImage接收参数,经过setValues()设置矩阵参数,而后Canvas调用drawBitmap绘图。效果以下:
上面给出了用坐标变换矩阵作出的各类效果,用坐标变换矩阵能够方面的调节图形的各类效果,
可是咱们看看Matrix类就能够发现,实际上,matrix类自己已经提供了许多相似的方法,咱们只要调用,就能够了。
setScale(float sx, float sy, float px, float py) 放大
setSkew(float kx, float ky, float px, float py) 斜切
setTranslate(float dx, float dy) 平移
setRotate(float degrees, float px, float py) 旋转
上面的函数提供了基本的变换平移,放大,旋转,斜切。为了作出更复杂的变换,同时没必要亲手去改动坐标变换矩阵,
Matrix类提供了许多Map方法,将原图形映射到目标点构成新的图形,
下面简述setPolyToPoly(float[] src, int srcIndex, float[] dst, int dstIndex, int pointCount) 的用法,但愿起到触类旁通的做用。
参数src和dst是分别存储了原图像的点和和指定的目标点的一维数组,数组中存储的坐标格式以下:
[x0, y0, x1, y1, x2,y2,...]
这个个函数将src中的坐标映射到dst中的坐标,实现图像的变换。
具体的例子能够参考APIDemos里的PolyToPoly,我在这里就再也不贴代码了,只讲一下函数是怎么变换图片的。下面是效果:
图中写1的是原图,写有2,3,4的是变换后的图形。如今分析2是怎么变换来的,变换的原坐标点和目的坐标点以下:
src=new float[] { 32, 32, 64, 32 }
dst=new float[] { 32, 32, 64, 48 }
从上图标示出的坐标看出原图的(32,32)映射到原图的(32,32),(64,32)映射到原图(64,48)这样的效果是图像放大了并且发生了旋转。这样的过程至关于(32,32)点不动,而后拉住图形(64,32)点并拉到(64,48)点处,这样图形必然会被拉伸放大而且发生旋转。最后用一个平移将图形移动到右边如今的位置。但愿可以好好理解这一过程,下面的3,4图是一样的道理。