一、Android变形矩阵——Matricx:

跟Android图像的色彩处理基本一样,只是将ColorMatrix换成了Matrix,ColorMatrix是4*5的矩阵,Matrix是3*3的。每个像素点表达了其坐标的X、Y信息:

当使用变换矩阵去处理每一个像素点的时候,与颜色矩阵的矩阵乘法一样,计算公式如下所示:

通常情况下,会让g=h=0,i=1,这样就使1=gX+hY+i    恒成立。因此,只需着重关注上面几个参数即可。

与色彩变换矩阵的初始矩阵一样,图形变换矩阵也有一个初始矩阵。就是对角线元素a、e、i为1,其他元素为0的矩阵,如下图所示:

图像的变形处理通常包含以下四类基本变换:

  • Translate——平移变换
  • Rotate——旋转变换
  • Scale——缩放变换
  • Skew——错切变换

1、平移变换

平移变换的坐标值变换过程就是将每个像素点都进行平移变换,当从P(x0,y0)平移到P(x1,y1)时,所需的平移矩阵如下所示:

2、旋转变换

旋转变换即指一个点围绕一个中心旋转到一个新的点。当从P(x0,y0)点,以坐标原点O为旋转中心旋转到P(x1,y1)时,可以将点的坐标都表达成OP与X轴正方向夹角的函数表达式(其中r为线段OP的长度,α为OP(x0,y0)与X轴正方向夹角,θ为OP(x0,y0)与OP(x1,y1)之间夹角),如下所示:

x0=rcosα
y0=rsinα
x1=rcos(α+θ)=rcosαcosθ−rsinαsinθ=x0cosθ−y0sinθ
y1=rsin(α+θ)=rsinαcosθ+rcosαsinθ=y0cosθ+x0sinθ

矩阵形式如下图所示:

前面是以坐标原点为旋转中心的旋转变换,如果以任意点O为旋转中心来进行旋转变换,通常需要以下三个步骤:

  • 将坐标原点平移到O点
  • 使用前面讲的以坐标原点为中心的旋转方法进行旋转变换
  • 将坐标原点还原

3、缩放变换

一个像素点是不存在缩放的概念的,但是由于图像是由很多个像素点组成的,如果将每个点的坐标都进行相同比例的缩放,最终就会形成让整个图像缩放的效果,缩放效果的公式如下

x1=K1x0
y1=K2y0

矩阵形式如下图所示:

4、错切变换

错切变换(skew)在数学上又称为Shear mapping(可译为“剪切变换“)或者Transvection(缩并),它是一种比较特殊的线性变换。错切变换的效果就是让所有点的X坐标(或者Y坐标)保持不变,而对应的Y坐标(或者X坐标)则按比例发生平移,且平移的大小和该点到Y轴(或者X轴)的距离成正比。错切变换通常包含两种——水平错切与垂直错切。

错切变换的计算公式如下:

  • 水平错切

x1=x0+K1y0
y1=y0

  • 垂直错切

x1=x0
y1=K2x0+y0

矩阵形式如下图

由上面的分析可以发现,这个图形变换3x3的矩阵与色彩变换矩阵一样,每个位置的元素所表示的功能是有规律的,总结如下:板面

可以发现,a、b、c、d、e、f这六个矩阵元素分别对应以下变换:

  • a和e控制Scale——缩放变换
  • b和d控制Skew——错切变换
  • a和e控制Trans——平移变换
  • a、b、d、e共同控制Rotate——旋转变换

通过类似色彩矩阵中模拟矩阵的例子来模拟变形矩阵。在图形变换矩阵中,同样是通过一个一维数组来模拟矩阵,并通过setValues()方法将一个一维数组转换为图形变换矩阵,代码如下所示:

   private float[] mImageMatrix = new float[9];

   Matrix matrix = new Matrix();
matrix.setValues(mImageMatrix);
 

当获得了变换矩阵后,就可以通过以下代码将一个图像以这个变换矩阵的形式绘制出来。

   canvas.drawBitmap(mBitmap, mMatrix, null);
 

示例代码:

activity:

  1. package com.example.androidmatrix;
  2. import android.app.Activity;
  3. import android.graphics.Bitmap;
  4. import android.graphics.Bitmap.Config;
  5. import android.graphics.BitmapFactory;
  6. import android.graphics.Canvas;
  7. import android.graphics.Matrix;
  8. import android.os.Bundle;
  9. import android.view.View;
  10. import android.widget.EditText;
  11. import android.widget.GridLayout;
  12. import android.widget.ImageView;
  13. public class TestMatrixActivity extends Activity {
  14. //定义组件
  15. private ImageView imageView;
  16. private GridLayout group;
  17. private Bitmap bitmap;
  18. private EditText[] edits = new EditText[9];
  19. private float[] edittexts = new float[9];
  20. protected void onCreate(Bundle savedInstanceState) {
  21. super.onCreate(savedInstanceState);
  22. setContentView(R.layout.testmatrix);
  23. imageView = (ImageView) findViewById(R.id.imageView);
  24. group = (GridLayout) findViewById(R.id.group);
  25. bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);
  26. imageView.setImageBitmap(bitmap);
  27. group.post(new Runnable() {
  28. public void run() {
  29. setNineEdits();
  30. fillNineEdits();
  31. }
  32. });
  33. }
  34. //创建9个编辑框
  35. private void setNineEdits(){
  36. int width = group.getWidth();
  37. int height = group.getHeight();
  38. for (int i = 0; i < edits.length; i++) {
  39. edits[i] = new EditText(TestMatrixActivity.this);
  40. edits[i].setWidth(width / 3);
  41. edits[i].setHeight(height / 3);
  42. group.addView(edits[i]);
  43. }
  44. }
  45. //给九个编辑框赋值
  46. private void fillNineEdits(){
  47. for (int i = 0; i < edits.length; i++) {
  48. if(i % 4 == 0){
  49. edits[i].setText(String.valueOf(1));
  50. }else{
  51. edits[i].setText(String.valueOf(0));
  52. }
  53. }
  54. }
  55. //重新获取九个编辑框的值
  56. private void getNineEdits(){
  57. for (int i = 0; i < edits.length; i++) {
  58. edittexts[i] = Float.valueOf(edits[i].getText().toString().trim());
  59. }
  60. }
  61. private void change(){
  62. Matrix matrix = new Matrix();
  63. Bitmap bmp = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Config.ARGB_8888);
  64. matrix.setValues(edittexts);
  65. Canvas canvas = new Canvas(bmp);
  66. canvas.drawBitmap(bitmap, matrix, null);
  67. imageView.setImageBitmap(bmp);
  68. }
  69. public void onChange(View view){
  70. getNineEdits();
  71. change();
  72. }
  73. public void onReset(View view){
  74. fillNineEdits();
  75. change();
  76. }
  77. }
package com.example.androidmatrix;

import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.GridLayout;
import android.widget.ImageView; public class TestMatrixActivity extends Activity {
//定义组件
private ImageView imageView;
private GridLayout group; private Bitmap bitmap;
private EditText[] edits = new EditText[9];
private float[] edittexts = new float[9];
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.testmatrix); imageView = (ImageView) findViewById(R.id.imageView);
group = (GridLayout) findViewById(R.id.group); bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);
imageView.setImageBitmap(bitmap); group.post(new Runnable() {
public void run() {
setNineEdits();
fillNineEdits();
}
});
} //创建9个编辑框
private void setNineEdits(){
int width = group.getWidth();
int height = group.getHeight();
for (int i = 0; i < edits.length; i++) {
edits[i] = new EditText(TestMatrixActivity.this);
edits[i].setWidth(width / 3);
edits[i].setHeight(height / 3);
group.addView(edits[i]);
}
}
//给九个编辑框赋值
private void fillNineEdits(){
for (int i = 0; i < edits.length; i++) {
if(i % 4 == 0){
edits[i].setText(String.valueOf(1));
}else{
edits[i].setText(String.valueOf(0));
}
}
} //重新获取九个编辑框的值
private void getNineEdits(){
for (int i = 0; i < edits.length; i++) {
edittexts[i] = Float.valueOf(edits[i].getText().toString().trim());
}
} private void change(){
Matrix matrix = new Matrix();
Bitmap bmp = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Config.ARGB_8888);
matrix.setValues(edittexts);
Canvas canvas = new Canvas(bmp);
canvas.drawBitmap(bitmap, matrix, null);
imageView.setImageBitmap(bmp);
} public void onChange(View view){
getNineEdits();
change();
} public void onReset(View view){
fillNineEdits();
change();
}
}

界面:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_width="match_parent"
  4. android:layout_height="match_parent"
  5. android:orientation="vertical" >
  6. <ImageView
  7. android:id="@+id/imageView"
  8. android:layout_width="fill_parent"
  9. android:layout_height="0dp"
  10. android:layout_weight="2" />
  11. <GridLayout
  12. android:id="@+id/group"
  13. android:layout_width="match_parent"
  14. android:layout_height="200dp"
  15. android:layout_weight="3"
  16. android:columnCount="3"
  17. android:rowCount="3" >
  18. </GridLayout>
  19. <LinearLayout
  20. android:layout_width="match_parent"
  21. android:layout_height="wrap_content"
  22. android:orientation="horizontal" >
  23. <Button
  24. android:layout_width="wrap_content"
  25. android:layout_height="wrap_content"
  26. android:layout_weight="1"
  27. android:onClick="onChange"
  28. android:text="生效" />
  29. <Button
  30. android:layout_width="wrap_content"
  31. android:layout_height="wrap_content"
  32. android:layout_weight="1"
  33. android:onClick="onReset"
  34. android:text="重置" />
  35. </LinearLayout>
  36. </LinearLayout>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" > <ImageView
android:id="@+id/imageView"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="2" /> <GridLayout
android:id="@+id/group"
android:layout_width="match_parent"
android:layout_height="200dp"
android:layout_weight="3"
android:columnCount="3"
android:rowCount="3" >
</GridLayout> <LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" > <Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:onClick="onChange"
android:text="生效" /> <Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:onClick="onReset"
android:text="重置" />
</LinearLayout> </LinearLayout>

效果图:

Android系统同样提供了一些API来简化矩阵的运算,我们不必每次都去设置矩阵的每一个元素值。Android中使用Matrix类来封装矩阵,并提供了以下几个操作方法来实现上面的四中变换方式:

  • matrix.setRotate()——旋转变换
  • matrix.setTranslate()——平移变换
  • matrix.setScale()——缩放变换
  • matrix.setSkew()——错切变换
  • matrix.preX和matrix.postY——提供矩阵的前乘和后乘运算

Matrix类的set方法会重置矩阵中的值,而post和pre方法不会,这两个方法常用来实现矩阵的混合作用。不过要注意的是,矩阵运算不满足乘法的交换律,所以矩阵乘法的前乘和后乘是两种不同的运算方式。举例说明,比如需要实现以下效果:

  • 先旋转45度
  • 再平移到(200, 200)

如果使用后乘运算,表示当前矩阵乘上参数代表的矩阵,代码如下所示:

        matrix.setRotate(45);
matrix.postTranslate(200, 200);

如果使用前乘运算,表示参数代表的矩阵乘上当前矩阵,代码如下所示:

        matrix.setTranslate(200, 200);
matrix.preRotate(45);

示例代码:

界面代码(就一个ImageView)省略...

  1. private ImageView imageView;
  2. private Bitmap bitmap;
  3. protected void onCreate(Bundle savedInstanceState) {
  4. super.onCreate(savedInstanceState);
  5. setContentView(R.layout.testmatrixmethod);
  6. imageView = (ImageView) findViewById(R.id.imageView);
  7. bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);
  8. imageView.setImageBitmap(changeImage());
  9. }
  10. private Bitmap changeImage(){
  11. Bitmap bmp = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Config.ARGB_8888);
  12. Matrix matrix = new Matrix();
  13. //旋转变换,参数是顺时针旋转角度
  14. matrix.setRotate(45);
  15. //平移变化,参数是要平移到的坐标
  16. //matrix.setTranslate(50, 50);
  17. //缩放变化
  18. //matrix.setScale(10, 10, 10, 10);
  19. //错切变换
  20. //matrix.setSkew(10, 10, 10, 10);
  21. Canvas canvas = new Canvas(bmp);
  22. canvas.drawBitmap(bitmap, matrix, null);
  23. return bmp;
  24. }
private ImageView imageView;
private Bitmap bitmap;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.testmatrixmethod); imageView = (ImageView) findViewById(R.id.imageView); bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);
imageView.setImageBitmap(changeImage());
} private Bitmap changeImage(){ Bitmap bmp = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Config.ARGB_8888);
Matrix matrix = new Matrix();
//旋转变换,参数是顺时针旋转角度
matrix.setRotate(45);
//平移变化,参数是要平移到的坐标
//matrix.setTranslate(50, 50);
//缩放变化
//matrix.setScale(10, 10, 10, 10);
//错切变换
//matrix.setSkew(10, 10, 10, 10);
Canvas canvas = new Canvas(bmp);
canvas.drawBitmap(bitmap, matrix, null);
return bmp;
}

效果图:

二、像素块分析

图像的特效处理有两种方式,即使用矩阵来进行图像变换和使用drawBitmapMesh()方法来进行处理。drawBitmapMesh()与操纵像素点来改变色彩的原理类似,只不过是把图像分成了一个个的小块,然后通过改变每一个图像块来修改整个图像。

drawBitmapMesh()方法代码如下:

public void drawBitmapMesh(Bitmap bitmap, int meshWidth, int meshHeight, float[] verts, int vertOffset, int[] colors, int colorOffset, Paint paint)

关键的参数如下:

bitmap:将要扭曲的图像

meshWidth:需要的横向网格数目

meshHeight :需要的纵向网格数目

verts:网格交叉点坐标数组

vertOffset:verts数组中开始跳过的(x, y)坐标对的数目

要使用drawBitmapMesh()方法就需先将图片分割为若干个图像块。所以,在图像上横纵各画N条线,而这横纵各N条线就交织成了NxN个点,而每个点的坐标则以x1,y1,x2,y2,...,xn,yn的形式保存在verts数组中。也就是说verts数组的每两位用来保存一个交织点,第一个是横坐标,第二个是纵坐标。而整个drawBitmapMesh()方法改变图像的方式,就是靠这些坐标值的改变来重新定义每一个图像块,从而达到图像效果处理的功能。

drawBitmapMesh()方法的功能非常强大,基本上可以实现所有的图像特效,但使用起来也非常复杂,其关键就是在于计算、确定新的交叉点的坐标。下面举例说明如何使用drawBitmapMesh()方法来实现一个旗帜飞扬的效果。

要想达到旗帜飞扬的效果,只需要让图片中每个交叉点的横坐标较之前不发生变化,而纵坐标较之前坐标呈现一个三角函数的周期性变化即可。

首先获取交叉点的坐标,并将坐标保存到orig数组中,其获取交叉点坐标的原理就是通过循环遍历所有的交叉线,并按比例获取其坐标,代码如下所示:

        mBitmap = BitmapFactory.decodeResource(context.getResources(), R.mipmap.test);
float bitmapWidth = mBitmap.getWidth();
float bitmapHeight = mBitmap.getHeight();
int index = 0;
for (int y = 0; y <= HEIGHT ; y++) {
float fy = bitmapHeight * y / HEIGHT;
for (int x = 0; x <= WIDTH; x++) {
float fx = bitmapWidth * x / WIDTH;
orig[index * 2] = verts[ index * 2] = fx;
//这里人为将坐标+100是为了让图像下移,避免扭曲后被屏幕遮挡
orig[index * 2 + 1] = verts[ index * 2 + 1] = fy + 100;
index++;
}
}

接下来,在onDraw()方法中改变交叉点的纵坐标的值,为了实现旗帜飘扬的效果,使用一个正弦函数sinx来改变交叉点纵坐标的值,而横坐标不变,并将变化后的值保存到verts数组中,代码如下所示:

    @Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
flagWave();
K += 0.1f;//将K的值增加
canvas.drawBitmapMesh(mBitmap, WIDTH, HEIGHT, verts, 0, null, 0, null);
invalidate();
} /**
* 按当前点所在的横坐标的位置来确定纵坐标的偏移量,其中A代表正弦函数中的振幅大小
*/
private void flagWave() {
for (int j = 0; j <= HEIGHT; j++) {
for (int i = 0; i <= WIDTH; i++) {
//在获取纵坐标的偏移量时,利用正弦函数的周期性给函数增加一个周期K * Math.PI,就是为了让图像能够动起来
float offsetY = (float) Math.sin(2 * Math.PI * i / WIDTH + K * Math.PI);
verts[(j * (WIDTH + 1) + i) * 2 + 1] = orig[(j * (WIDTH + 1) + i) * 2 + 1] + offsetY * A;
}
}
}

这样,每次在重绘时,通过改变相位来改变偏移量,从而造成一个动态的效果,就好象旗帜在风中飘扬一样,效果图如下(这里应该是动态的,似乎一个飘扬的旗帜)。

主要代码:

  1. package com.mfc.myview;
  2. import android.content.Context;
  3. import android.graphics.Bitmap;
  4. import android.graphics.BitmapFactory;
  5. import android.graphics.Canvas;
  6. import android.util.AttributeSet;
  7. import android.view.View;
  8. import com.example.androidmatrix.R;
  9. public class FlagBitmapMeshView extends View {
  10. private final int WIDTH = 200;
  11. private final int HEIGHT = 200;
  12. private int COUNT = (WIDTH + 1) * (HEIGHT + 1);
  13. private float[] verts = new float[COUNT * 2];
  14. private float[] orig = new float[COUNT * 2];
  15. private Bitmap bitmap;
  16. private float A;
  17. private float k = 1;
  18. public FlagBitmapMeshView(Context context) {
  19. super(context);
  20. initView(context);
  21. }
  22. public FlagBitmapMeshView(Context context, AttributeSet attrs) {
  23. super(context, attrs);
  24. initView(context);
  25. }
  26. public FlagBitmapMeshView(Context context, AttributeSet attrs,
  27. int defStyleAttr) {
  28. super(context, attrs, defStyleAttr);
  29. initView(context);
  30. }
  31. private void initView(Context context) {
  32. setFocusable(true);
  33. bitmap = BitmapFactory.decodeResource(context.getResources(),
  34. R.drawable.we);
  35. float bitmapWidth = bitmap.getWidth();
  36. float bitmapHeight = bitmap.getHeight();
  37. int index = 0;
  38. for (int y = 0; y <= HEIGHT; y++) {
  39. float fy = bitmapHeight * y / HEIGHT;
  40. for (int x = 0; x <= WIDTH; x++) {
  41. float fx = bitmapWidth * x / WIDTH;
  42. orig[index * 2 + 0] = verts[index * 2 + 0] = fx;
  43. orig[index * 2 + 1] = verts[index * 2 + 1] = fy + 100;
  44. index += 1;
  45. }
  46. }
  47. A = 50;
  48. }
  49. @Override
  50. protected void onDraw(Canvas canvas) {
  51. flagWave();
  52. k += 0.1F;
  53. canvas.drawBitmapMesh(bitmap, WIDTH, HEIGHT,
  54. verts, 0, null, 0, null);
  55. invalidate();
  56. }
  57. private void flagWave() {
  58. for (int j = 0; j <= HEIGHT; j++) {
  59. for (int i = 0; i <= WIDTH; i++) {
  60. verts[(j * (WIDTH + 1) + i) * 2 + 0] += 0;
  61. float offsetY =
  62. (float) Math.sin((float) i / WIDTH * 2 * Math.PI +
  63. Math.PI * k);
  64. verts[(j * (WIDTH + 1) + i) * 2 + 1] =
  65. orig[(j * WIDTH + i) * 2 + 1] + offsetY * A;
  66. }
  67. }
  68. }
  69. }
package com.mfc.myview;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.View; import com.example.androidmatrix.R; public class FlagBitmapMeshView extends View { private final int WIDTH = 200;
private final int HEIGHT = 200;
private int COUNT = (WIDTH + 1) * (HEIGHT + 1);
private float[] verts = new float[COUNT * 2];
private float[] orig = new float[COUNT * 2];
private Bitmap bitmap;
private float A;
private float k = 1; public FlagBitmapMeshView(Context context) {
super(context);
initView(context);
} public FlagBitmapMeshView(Context context, AttributeSet attrs) {
super(context, attrs);
initView(context);
} public FlagBitmapMeshView(Context context, AttributeSet attrs,
int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView(context);
} private void initView(Context context) {
setFocusable(true);
bitmap = BitmapFactory.decodeResource(context.getResources(),
R.drawable.we);
float bitmapWidth = bitmap.getWidth();
float bitmapHeight = bitmap.getHeight();
int index = 0;
for (int y = 0; y <= HEIGHT; y++) {
float fy = bitmapHeight * y / HEIGHT;
for (int x = 0; x <= WIDTH; x++) {
float fx = bitmapWidth * x / WIDTH;
orig[index * 2 + 0] = verts[index * 2 + 0] = fx;
orig[index * 2 + 1] = verts[index * 2 + 1] = fy + 100;
index += 1;
}
}
A = 50;
} @Override
protected void onDraw(Canvas canvas) {
flagWave();
k += 0.1F;
canvas.drawBitmapMesh(bitmap, WIDTH, HEIGHT,
verts, 0, null, 0, null);
invalidate();
} private void flagWave() {
for (int j = 0; j <= HEIGHT; j++) {
for (int i = 0; i <= WIDTH; i++) {
verts[(j * (WIDTH + 1) + i) * 2 + 0] += 0;
float offsetY =
(float) Math.sin((float) i / WIDTH * 2 * Math.PI +
Math.PI * k);
verts[(j * (WIDTH + 1) + i) * 2 + 1] =
orig[(j * WIDTH + i) * 2 + 1] + offsetY * A;
}
}
}
}

使用drawBitmapMesh()方法可以创建很多复杂的图像效果,但是对它的使用也相对复杂,需要我们对图像处理有很深厚的功底。同时,对算法的要求也比较高,需要计算各种特效下不同的坐标点变化规律,从而设计出不同的特效。

Android图像处理之图形特效处理的更多相关文章

  1. Android L(5.0)源码之图形与图像处理之图形特效——Matrix

    最近在研究android 5.0的gallery模块,学习了相关的知识点,准备写点博客总结一下,有时间了会补充完整

  2. Android图像处理之熔铸特效

    代码: package com.color; import android.content.Context; import android.graphics.Bitmap; import androi ...

  3. android 图像处理系列合集

    为了便于大家对滤镜算法的学习,以后发布的图像处理滤镜系列帖子会在这里汇总,本人第一次写合集,写得不好的地方大家请见谅,手头上虽然有一些滤镜的算法,但是大多不是android版的,教程里的代码大多是我借 ...

  4. Android图像处理实例教程

    Android图像处理实例教程 原始出处 http://vaero.blog.51cto.com/4350852/856750

  5. 多种的android进度条的特效源码

    多种的android进度条的特效源码,这个源码是在源码天堂那个网站上转载过来的,我已经修改一部分了,感觉很实用的,大家可以学习一下吧,我就不上传源码了,大家可以直接到那个网站上下载吧. 源码天堂下载地 ...

  6. Android图像处理1

    项目开发要用,在慕课中学习了一下关于Android图像处理的相关功能,并进行了整理. 在Android中,我们通过最基本的改变图像的RGBA值,改变图像的颜色与饱和度. Android中有ColorM ...

  7. Qt 图形特效(Graphics Effect)介绍

    原文链接:Qt 图形特效(Graphics Effect)介绍 QGraphicsEffect也是Qt-4.6引入的一个新功能.它让给图形元素QGraphicsItem增加更佳视觉效果的编程变得非常简 ...

  8. Android图像处理 - 高斯模糊的原理及实现

    欢迎大家前往云+社区,获取更多腾讯海量技术实践干货哦~ 由 天天P图攻城狮 发布在云+社区 作者简介:damonxia(夏正冬),天天P图Android工程师 前言 高斯模糊是图像处理中几乎每个程序员 ...

  9. android系统联系人分组特效实现(2)---字母表快速滚动

    要实现这种功能,只需要在   android系统联系人分组特效实现(1)---分组导航和挤压动画  的基础上再加上一个自定义控件即可完成. 1.新建项目,继续新建一个java类,BladeView,用 ...

随机推荐

  1. 给DBGrid动态赋值后,如何用程序指定某行某列为当前焦点?(100分)

    哈哈,我弄出来了.在大富翁上搜索的.Form1.DBGrid1.SelectedIndex := 4;Form1.DBGrid1.SetFocus;这样就行了.谢谢你! --------------- ...

  2. MATLAB灰色关联度分析

    目录 1.释名 2.举例 3.操作步骤与原理详解 4.总结 5.附录:MATLAB代码 @ 1.释名 灰色关联度分析(Grey Relation Analysis,GRA),是一种多因素统计分析的方法 ...

  3. 【CUDA开发】 CUDA Thrust 规约求和

    1. 使用 Thrust Thrust 是一个开源的 C++ 库,用于开发高性能并行应用程序,以 C++ 标准模板库为蓝本实现. 官方文档见这里:CUDA Thrust /* ... */ float ...

  4. 通过java 来实现对多个文件的内容合并到一个文件中

    现在有多个txt文本文件,需要把这么多个文件的内容都放到一个文件中去 以下是实现代码 package com.SBgong.test; import java.io.*; public class F ...

  5. MyBatis动态SQL第一篇之实现多条件查询(if、where、trim标签)

    一.动态SQL概述 以前在使用JDBC操作数据时,如果查询条件特别多,将条件串联成SQL字符串是一件痛苦的事情.通常的解决方法是写很多的if-else条件语句对字符串进行拼接,并确保不能忘了空格或在字 ...

  6. 使用idea关联mysql时报错Server returns invalid timezone. Go to 'Advanced' tab and set 'serverTimezon'

    版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/liuqiker/article/detai ...

  7. Luogu P2617 Dynamic Rankings(整体二分)

    题目 动态区间第K小模板题. 一个非常可行的办法是BIT套动态开点权值SegTree,但是它跑的实在太慢了. 然后由于这题并没有强制在线,所以我们可以使用整体二分来吊打树套树. 当然如果强制在线的话就 ...

  8. MySQL创表--分页--自关联--

    创建表book create table t_book( id int unsigned auto_increment primary key, bookName varchar(255) defau ...

  9. JAVA break、continue和return的区别

    控制跳转:continue和break的区别,以为return Continue在循环中使用,一般在for中使用 Break:跳出单重循环,常和switch搭配使用. 效果区别 Break的结果如下: ...

  10. C语言经典100例(51-100)

    [程序51] 题目:学习使用按位与 & . 分析:0&0=0; 0&1=0; 1&0=0; 1&1=1 #include "stdio.h" ...