«

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

时间:2024-3-2 17:43     作者:韩俊     分类: Android


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

完成对图像的基本操作:

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(new float[]{

.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(new float[]{

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(new float[]{//设计亮度矩阵

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(new float[]{//对比度矩阵

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() {

public voidonProgressChanged(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(new float[]{//对比度亮度矩阵

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" />


项目完成!




标签: android

热门推荐