木瓜妮子多媒体开发教程---第二天---Android下对图像的几何操作

来源:互联网 发布:淘宝最好的推广方式 编辑:程序博客网 时间:2024/04/28 00:56

几何操作 ----  图像的基本操作


完成对图像的基本操作:

1、打开一张图片并将图片显示在界面上。

2、采用进度条控制图片的缩放,旋转,亮度和对比度调节。

那么比较重要的技术点在于:

1、掌握从图库中返回图像的操作,学会将图放置在ImageView控件上,学会使用画笔、画布类作图。

2、掌握setScale、setRotate的使用,熟悉亮度和对比度系数矩阵。

3、了解Intent显式的启动相册Activity的操作,并与原Activity进行通信。

  Android提供了API文档,查阅文档得到类中方法的接口和demo。

本教程所使用的主要类包括:

 android.graphics.Bitmap;

 android.graphics.BitmapFactory;

 android.graphics.Canvas;

 android.graphics.ColorMatrix;

 android.graphics.ColorMatrixColorFilter;

 android.graphics.Matrix;

 android.graphics.Paint;

 android.widget.SeekBar;

 android.widget.SeekBar.OnSeekBarChangeListener;


1.Android如何获得图像资源?

         Android获得图像资源有三种常用的方法:

         1.图片放在sdcard中,Bitmap imageBitmap = BitmapFactory.decodeFile(path) ,其中path 是图片的绝对路径;

         2. 图片在项目的res-->drawable文件夹下,Drawabledrawable  = getResource().getDrawable(R.drawable.pic);         

 3. 通过显式意图,从拍照或者图库中返回图像。

public void onClick(View v) {
Intent choosephotoIntent = new Intent(Intent.ACTION_PICK,android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);//打开图库文件
startActivityForResult(choosephotoIntent,1);//图库返回结果
}

onActivityResult(requestCode, resultCode, data)方法中添加

Bitmap cameraBitmap = (Bitmap) data.getExtras().get("data");//得到图片

2.图像几何操作:

         数字图像的几何变换是计算机图像处理领域的一个重要课题,它使原始图像按照实际需要产生大小、形状或者位置的变化。根据变换的性质,图像的几何变换可分为位置变换(平移、镜像、旋转)、形状变换(缩放、截取、错切)和复合变换等。

         在Android API中有一个Matrix(矩阵)类,可以完成对当前位图对象的重新绘制,也可以绘制一个全新的位图对象。在进行图像的空间的几何变换时可以选择使用该类,完成对图像的旋转、裁剪、缩放或是更改图像的坐标空间。Matrix类是有9个数字的数组来表示转换的。数字可以手动输入,也可以通过进度条控制输入。

         简单举例:

    Matrixmatrixzoom =new Matrix();

    matrixzoom.setValues(newfloat[]{

                  .5f,0,0,

                  0,1,0,

                  0,0,1

              });

    canvas.drawBitmap(bmp,matrixzoom, paint);

         通过手动设置缩放矩阵,完成对图像的操作。操作的结果是在x轴上图像被压缩了50%,由此可见第一行的.5f影响了x的坐标值,使图像被压缩了50%。若同时将第二行第二列的1改为.5f,则图像在x轴和y轴方向被同时压缩50%,如果改为2,则为扩展一倍。

 

    Matrix matrixzoom =new Matrix();

    matrixzoom.setValues(newfloat[]{

               1,.5f,0,

              0,1,0,

              0,0,1

              });

    canvas.drawBitmap(bmp,matrixzoom, paint);

    操作的结果是导致图像的倾斜,因为第一行第二列的.5f使得每个像素的x值需要根据像素的y值进行改变,即X = X+0.5Y,当y值增加时,x值也会随之增加,空出来的部分用黑色补齐,图片就产生了倾斜的效果。吐舌头

    如果不想通过自己手动修改矩阵来使图片缩放,可以采用下面的内置方法实现: 

    Matrix matrixzoom =newMatrix();

    matrixzoom.setScale(.5f,.5f);

    canvas.drawBitmap(bmp,matrixzoom, paint);

    此操作的效果是对图片整体进行了50%的缩放,其中第一个参数控制X轴,第二个参数控制Y轴。

 

    Matrix matrixrotate =newMatrix();

    matrixrotate.setRotate(30);

    canvas.drawBitmap(bmp,matrixrotate, paint);

         操作的结果是图像产生了30度的顺时针旋转,如果设置为负数则会逆时针旋转图像,旋转的中心为左上角。

 

    matrixrotate.setRotate(30,bmp.getWidth()/2,bmp.getHeight()/2);

    操作可以保证图像的中心点是旋转点。

 

3.图像颜色值处理:

         类似于Matrix对象的使用方法,Android提供了一个ColorMatrix类库,这个类可以改变Paint对象。ColorMatrix也是一个数字数组,不同于操作x、y、z坐标,它操作的是RGB颜色值和Alpha值。

         在ColorMatrix中共包含20个浮点数,第一行包含了在单个像素的红色部分上发生的操作,第二行影响了绿色部分,第三行影响蓝色部分,最后一行的操作数可控制像素的Alpha值。

        float lightness= 20;

    ColorMatrixmatrixlightness =newColorMatrix();

    matrixlightness.set(newfloat[]{//设计亮度矩阵

              1,0,0,0,lightness,

              0,1,0,0,lightness,

              0,0,1,0,lightness,

              0,0,0,1,0

           });

    paint.setColorFilter(newColorMatrixColorFilter(matrixlightness));

    Matrixmatrix_lightness =newMatrix();

    canvas.drawBitmap(bmp,matrix_lightness, paint);

         此操作的结果是可提升图片亮度。

 

    float contrast = 3;

    ColorMatrixmatrixcontrast =newColorMatrix();

    matrixcontrast.set(newfloat[]{//对比度矩阵

                     contrast,0,0,0,0,

                     0,contrast,0,0,0,

                     0,0,contrast,0,0,

                     0,0,0,1,0

              });

    paint.setColorFilter(newColorMatrixColorFilter(matrixcontrast));

    Matrixmatrix_contrast =newMatrix();

    canvas.drawBitmap(bmp,matrix_contrast, paint);

此操作的结果是提升了图片的对比度。

 

4.SeekBar设计:

通常我们采用进度条seekbar来控制一个控件的进度。在这里,我们可以用来控制缩放倍数、旋转角度和亮度、对比度的值。

    <SeekBar

       android:id="@+id/seekBar1"

       android:layout_width="match_parent"

       android:layout_height="wrap_content"

       android:layout_alignLeft="@+id/seekBar2"

       android:max="255"

       android:progress="50"/>

默认seekbar的最大值为100,Android:max可以重新设定最大值,Android:progress可以设定当前值。

 

seekbar1.setOnSeekBarChangeListener(newOnSeekBarChangeListener() {

    publicvoidonProgressChanged(SeekBar arg0, intarg1, boolean arg2) {

    float zoom= (float) arg1 / 20;

    Matrixmatrixzoom =new Matrix();

    matrixzoom.setScale(zoom,zoom);//通过构建缩放矩阵完成功能

       canvas.drawBitmap(bitmap,matrixzoom, paint); }

   

    public voidonStartTrackingTouch(SeekBar arg0) {      

    }

    public voidonStopTrackingTouch(SeekBar arg0) {

    }

在Mainactivity中对seekbar进行动作设置。为Seekbar设置一个侦听器,当进度条被拖动时,即执行onProgressChanged方法。对onProgressChanged方法进行复写,arg1表示当前拖动条进度,赋值给zoom变量,用来控制缩放的倍数。

onStartTrackingTouch在按下拖动条瞬间执行,onStopTrackingTouch在松开拖动条的瞬间执行。


如果想要实现亮度和对比度的同时变化,矩阵应该怎样构成呢?

结合了对比度和亮度矩阵,构成方法是这样的,同时调节可以调节图片的多种曝光效果:

    matrix.set(newfloat[]{//对比度亮度矩阵

                     contrast,0,0,0,lightness,

                     0,contrast,0,0,lightness,

                     0,0,contrast,0,lightness,

                     0,0,0,1,0

              });


----------------------讲解的部分就到这里,下面开始要发干货了,小伙伴们准备接招!----------------------------

MainActivity.java部分


//功能:实现对原图的编辑:缩放、旋转、亮度、对比度的调节。

public class MainActivity extends Activity {


private SeekBar sb1 = null;
private SeekBar sb2 = null;
private SeekBar sb3 = null;
private SeekBar sb4 = null;
private Button choosephoto = null;
private ImageView originalphoto = null;
private ImageView secondphoto = null;
private Bitmap bmp = null;
private Bitmap bmp1;


@Override
protected void onCreate(Bundle savedInstanceState) {
setContentView(R.layout.activity_main);
choosephoto = (Button) this.findViewById(R.id.Bton1);// 得到控件
originalphoto = (ImageView) this.findViewById(R.id.ImgView1);
secondphoto = (ImageView) this.findViewById(R.id.ImgView2);
choosephoto.setOnClickListener(new View.OnClickListener() {// 为“打开图片”按钮设置动作,采用匿名内部类的方式,此方式虽然书写方便但是造成代码混乱。
@Override
public void onClick(View v) {
Intent choosephotoIntent = new Intent(//打开一个显式意图
Intent.ACTION_PICK,
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);// 打开图库文件
startActivityForResult(choosephotoIntent, 1);// 图库返回结果
}
});
}


protected void onActivityResult(int requestCode, int resultCode, Intent data) {// 对返回结果的处理:各种对图像的编辑操作
super.onActivityResult(requestCode, resultCode, data);


if (resultCode == RESULT_OK) {
Uri imageuri = data.getData();
System.out.println("the Uri is " + imageuri);
Display currentDisplay = getWindowManager().getDefaultDisplay();// 为了能快速加载图片,需要将原图缩放到合适大小,“合适”的标准由宽高wratio和hratio来决定。

int dw = currentDisplay.getWidth() / 2 - 20;
int dh = currentDisplay.getHeight() / 2 - 10;
System.out.println("the dw is " + dw);
System.out.println("the dh is " + dh);

try {
BitmapFactory.Options bmpopt = new BitmapFactory.Options();//
bmpopt.inJustDecodeBounds = true;
System.out.println("bitmap is decode ");

bmp = BitmapFactory.decodeStream(getContentResolver()
.openInputStream(imageuri), null, bmpopt);

int hratio = (int) Math.ceil(bmpopt.outHeight / (float) dh);// 率=图片高/屏幕高
int wratio = (int) Math.ceil(bmpopt.outWidth / (float) dw);// 率=图片宽/屏幕宽
System.out.println("the hratio is " + hratio);
System.out.println("the wratio is " + wratio);
if (hratio > 1 && wratio > 1) {// 判断得到合适的缩放比率
if (hratio >= wratio) {
bmpopt.inSampleSize = hratio;
} else {
bmpopt.inSampleSize = wratio;
}
}

bmpopt.inJustDecodeBounds = false;
bmp = BitmapFactory.decodeStream(getContentResolver()
.openInputStream(imageuri), null, bmpopt);
originalphoto.setImageBitmap(bmp);// 显示经过缩放后的图库原图片


bmp1 = Bitmap.createBitmap(bmp.getWidth(), bmp.getHeight(),
bmp.getConfig());// 创建新位图
final Canvas canvas = new Canvas(bmp1);// 画布
final Paint paint = new Paint();// 画笔
paint.setAntiAlias(true);// 消除锯齿


canvas.drawBitmap(bmp, 0, 0, paint);
secondphoto.setImageBitmap(bmp1);// 显示新位图,初始时和原图一致


sb1 = (SeekBar) findViewById(R.id.seekBar1);// 得到四个控制条控件
sb2 = (SeekBar) findViewById(R.id.seekBar2);
sb3 = (SeekBar) findViewById(R.id.seekBar3);
sb4 = (SeekBar) findViewById(R.id.seekBar4);


sb1.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {// 设置控制条操作


@Override
public void onProgressChanged(SeekBar arg0, int arg1,
boolean arg2) {


float zoom = (float) arg1 / 64;
Matrix matrixzoom = new Matrix();
matrixzoom.setValues(new float[] { .5f, 0, 0, 0, 1, 0,
0, 0, 1 });
matrixzoom.setScale(zoom, zoom);// 通过构建缩放矩阵完成功能
canvas.drawBitmap(bmp, matrixzoom, paint);
secondphoto.setImageBitmap(bmp1);
}


@Override
public void onStartTrackingTouch(SeekBar arg0) {


}


@Override
public void onStopTrackingTouch(SeekBar arg0) {


}
});


sb2.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {


@Override
public void onStopTrackingTouch(SeekBar arg0) {


}


@Override
public void onStartTrackingTouch(SeekBar arg0) {


}


@Override
public void onProgressChanged(SeekBar arg0, int arg1,
boolean arg2) {


float rotate = (float) arg1 * 360 / 255;
Matrix matrixrotate = new Matrix();
matrixrotate.setRotate(rotate, bmp.getWidth() / 2,
bmp.getHeight() / 2);// 设置旋转操作,并约束了宽高
canvas.drawBitmap(bmp, matrixrotate, paint);
secondphoto.setImageBitmap(bmp1);
}
});


sb3.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {


@Override
public void onStopTrackingTouch(SeekBar arg0) {


}


@Override
public void onStartTrackingTouch(SeekBar arg0) {


}


@Override
public void onProgressChanged(SeekBar arg0, int arg1,
boolean arg2) {
float lightness = (arg1 - 128) / 3;
ColorMatrix matrixlightness = new ColorMatrix();
matrixlightness.set(new float[] {// 设计亮度矩阵
1, 0, 0, 0, lightness, 0, 1, 0, 0, lightness,
0, 0, 1, 0, lightness, 0, 0, 0, 1, 0 });
paint.setColorFilter(new ColorMatrixColorFilter(
matrixlightness));
Matrix matrix_lightness = new Matrix();
canvas.drawBitmap(bmp, matrix_lightness, paint);// 很不幸,这里的亮度和对比度只能单独针对原图变化,而不能混合使用。
secondphoto.setImageBitmap(bmp1);
}
});


sb4.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {


@Override
public void onStopTrackingTouch(SeekBar arg0) {


}


@Override
public void onStartTrackingTouch(SeekBar arg0) {


}


@Override
public void onProgressChanged(SeekBar arg0, int arg1,
boolean arg2) {
float contrast = (float) arg1 / 16;
ColorMatrix matrixcontrast = new ColorMatrix();
matrixcontrast.set(new float[] {// 对比度矩阵
contrast, 0, 0, 0, 0, 0, contrast, 0, 0, 0, 0,
0, contrast, 0, 0, 0, 0, 0, 1, 0 });
paint.setColorFilter(new ColorMatrixColorFilter(
matrixcontrast));
Matrix matrix_contrast = new Matrix();
canvas.drawBitmap(bmp, matrix_contrast, paint);
secondphoto.setImageBitmap(bmp1);
}
});


} catch (FileNotFoundException e) {// 捕获异常的操作
Log.v("error", e.toString());
}
}
}
}

 

布局文件  


<RelativeLayout 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"
    tools:context=".MainActivity" >


    <TextView
        android:id="@+id/textView1"
        android:layout_width="50dp"
        android:layout_height="wrap_content"
        android:text="@string/zoom"
        android:textColor="#638"
        android:textStyle="bold" />


    <SeekBar
        android:id="@+id/seekBar1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/seekBar2"
        android:max="255"
        android:progress="50"
        android:secondaryProgress="75" />


    <TextView
        android:id="@+id/textView2"
        android:layout_width="50dp"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignTop="@+id/seekBar2"
        android:text="@string/rotate"
        android:textColor="#638"
        android:textStyle="bold" />


    <SeekBar
        android:id="@+id/seekBar2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_below="@+id/seekBar1"
        android:layout_toRightOf="@+id/textView2"
        android:max="255"
        android:progress="50"
        android:secondaryProgress="75" />


    <TextView
        android:id="@+id/textView3"
        android:layout_width="50dp"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignTop="@+id/seekBar3"
        android:text="@string/brightness"
        android:textColor="#638"
        android:textStyle="bold" />


    <SeekBar
        android:id="@+id/seekBar3"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_below="@+id/seekBar2"
        android:layout_toRightOf="@+id/textView3"
        android:max="255"
        android:progress="50"
        android:secondaryProgress="75" />


    <TextView
        android:id="@+id/textView4"
        android:layout_width="50dp"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignTop="@+id/seekBar4"
        android:text="@string/contrast"
        android:textColor="#638"
        android:textStyle="bold" />


    <SeekBar
        android:id="@+id/seekBar4"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_below="@+id/seekBar3"
        android:layout_toRightOf="@+id/textView4"
        android:max="100"
        android:progress="20"
        android:secondaryProgress="30" />


    <ImageView
        android:id="@+id/ImgView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_marginBottom="20dp"
        android:layout_alignParentLeft="true"
        android:background="#444" />


    <ImageView
        android:id="@+id/ImgView2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_marginBottom="20dp"
        android:layout_alignParentRight="true"
        android:background="#eee" />


    <Button
        android:id="@+id/Bton1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_below="@+id/seekBar4"
        android:text="@string/bt1" />


</RelativeLayout>


Manifest.xml文件中别忘了添加:

    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> 


项目完成!




0 0
原创粉丝点击