4000 Android 使用opencv实现抠图
2017-12-09 11:35
951 查看
1.openCv配置从https://github.com/opencv/opencv/releases/tag/3.3.0下载对应的android版本a. import module 选择b.还要配置so文件来调取opencv的接口,在main文件夹下创建jniLibs文件夹,如下图:把下载的native目录下libs文件下的所有文件拷入jniLibs文件下c.别忘了把module里的build.gradle修改成和你一样的gradle配置d.配置manifiest在application标签前添加
<uses-permission android:name="android.permission.CAMERA"/> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-feature android:name="android.hardware.camera" android:required="false"/> <uses-feature android:name="android.hardware.camera.autofocus" android:required="false"/> <uses-feature android:name="android.hardware.camera.front" android:required="false"/> <uses-feature android:name="android.hardware.camera.front.autofocus" android:required="false"/>
在application标签后添加
<supports-screens android:resizeable="true" android:smallScreens="true" android:normalScreens="true" android:largeScreens="true" android:anyDensity="true" />
e.在Activity中实现opencv的初始化
private BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this) { @Override public void onManagerConnected(int status) { switch (status) { case LoaderCallbackInterface.SUCCESS: { Log.i(TAG, "OpenCV loaded successfully"); } break; default: { super.onManagerConnected(status); } break; } } }; @Override public void onResume() { super.onResume(); if (!OpenCVLoader.initDebug()) { Log.d("OpenCV", "Internal OpenCV library not found. Using OpenCV Manager for initialization"); OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_3_0_0, this, mLoaderCallback); } else { Log.d("OpenCV", "OpenCV library found inside package. Using it!"); mLoaderCallback.onManagerConnected(LoaderCallbackInterface.SUCCESS); } }
到此为此,opencv配置完成,进入正题,首先先看下效果:
其实实现抠图的效果也就是调用opencv提供的grabcut函数,函数方法如下:
private Bitmap cupBitmap(Bitmap bitmap,int x,int y,int width,int height){ Mat img = new Mat(); //缩小图片尺寸 // Bitmap bm = Bitmap.createScaledBitmap(bitmap,bitmap.getWidth(),bitmap.getHeight(),true); //bitmap->mat Utils.bitmapToMat(bitmap, img); //转成CV_8UC3格式 Imgproc.cvtColor(img, img, Imgproc.COLOR_RGBA2RGB); //设置抠图范围的左上角和右下角 Rect rect = new Rect(x,y,width,height); //生成遮板 Mat firstMask = new Mat(); Mat bgModel = new Mat(); Mat fgModel = new Mat(); Mat source = new Mat(1, 1, CvType.CV_8U, new Scalar(Imgproc.GC_PR_FGD)); //这是实现抠图的重点,难点在于rect的区域,为了选取抠图区域,我借鉴了某大神的自定义裁剪View,返回坐标和宽高 Imgproc.grabCut(img, firstMask, rect, bgModel, fgModel,5, Imgproc.GC_INIT_WITH_RECT); Core.compare(firstMask, source, firstMask, Core.CMP_EQ); //抠图 Mat foreground = new Mat(img.size(), CvType.CV_8UC3, new Scalar(255, 255, 255)); img.copyTo(foreground, firstMask); //mat->bitmap Bitmap bitmap1 = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888); Utils.matToBitmap(foreground,bitmap1); return bitmap1; }
废话不多说,奉上干粮:
import android.app.ProgressDialog;import android.content.Context;import android.content.Intent;import android.database.Cursor;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.graphics.RectF;import android.graphics.drawable.BitmapDrawable;import android.net.Uri;;import android.os.Environment;import android.provider.MediaStore;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.util.Log;import android.view.View;import android.widget.Button;import android.widget.ImageView;import android.widget.Toast;import org.opencv.android.BaseLoaderCallback;import org.opencv.android.LoaderCallbackInterface;import org.opencv.android.OpenCVLoader;import org.opencv.android.Utils;import org.opencv.core.Core;import org.opencv.core.CvType;import org.opencv.core.Mat;import org.opencv.core.Rect;import org.opencv.core.Scalar;import org.opencv.imgproc.Imgproc;import java.io.File;import java.io.FileOutputStream;import java.io.IOException;public class MainActivity extends AppCompatActivity implements View.OnClickListener {static final int REQUEST_OPEN_IMAGE = 1;private static final String TAG ="xxx";MyCropView cropView;String mCurrentPhotoPath;boolean targetChose = false;ProgressDialog dlg;private Button select;private Button cut;private Button modify;private Button saveImage;private Bitmap originalBitmap;private ImageView choiceView;private boolean hasCut =false;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);cropView = (MyCropView) findViewById(R.id.myCropView);select = (Button) findViewById(R.id.btn_gray_process);cut = (Button) findViewById(R.id.btn_cut_process);modify = (Button) findViewById(R.id.btn_modify_process);saveImage = (Button) findViewById(R.id.btn_save_process);choiceView = (ImageView) findViewById(R.id.croppedImageView);select.setOnClickListener(this);cut.setOnClickListener(this);saveImage.setOnClickListener(this);modify.setOnClickListener(this);dlg = new ProgressDialog(this);}private BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this) { @Override public void onManagerConnected(int status) { switch (status) { case LoaderCallbackInterface.SUCCESS: { Log.i(TAG, "OpenCV loaded successfully"); } break; default: { super.onManagerConnected(status); } break; } } }; @Override public void onResume() { super.onResume(); if (!OpenCVLoader.initDebug()) { Log.d("OpenCV", "Internal OpenCV library not found. Using OpenCV Manager for initialization"); OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_3_0_0, this, mLoaderCallback); } else { Log.d("OpenCV", "OpenCV library found inside package. Using it!"); mLoaderCallback.onManagerConnected(LoaderCallbackInterface.SUCCESS); } }//从图库中选择图片public void setPic(){originalBitmap = BitmapFactory.decodeFile(mCurrentPhotoPath);cropView.setBmpPath(mCurrentPhotoPath);}@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) {switch (requestCode) {case REQUEST_OPEN_IMAGE:if (resultCode == RESULT_OK) {Uri imgUri = data.getData();String[] filePathColumn = { MediaStore.Images.Media.DATA };Cursor cursor = getContentResolver().query(imgUri, filePathColumn,null, null, null);cursor.moveToFirst();int colIndex = cursor.getColumnIndex(filePathColumn[0]);mCurrentPhotoPath = cursor.getString(colIndex);cursor.close();setPic();}break;}}//选择剪切区域private void selectImageCut(){targetChose = true;try{Bitmap cropBitmap = cropView.getCroppedImage();choiceView.setImageBitmap(cropBitmap);}catch (Exception e){e.printStackTrace();}}@Overridepublic void onClick(View v) {switch (v.getId()){case R.id.btn_gray_process:Intent getPictureIntent = new Intent(Intent.ACTION_GET_CONTENT);getPictureIntent.setType("image/*");Intent pickPictureIntent = new Intent(Intent.ACTION_PICK,MediaStore.Images.Media.EXTERNAL_CONTENT_URI);Intent chooserIntent = Intent.createChooser(getPictureIntent, "Select Image");chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, new Intent[] {pickPictureIntent});startActivityForResult(chooserIntent, REQUEST_OPEN_IMAGE);break;case R.id.btn_cut_process://抠图是耗时的过程,子线程中运行,并dialog提示if (targetChose){dlg.show();dlg.setMessage("正在抠图...");final RectF croppedBitmapData = cropView.getCroppedBitmapData();final int croppedBitmapWidth = cropView.getCroppedBitmapWidth();final int croppedBitmapHeight = cropView.getCroppedBitmapHeight();new Thread(new Runnable() {@Overridepublic void run() {final Bitmap bitmap = cupBitmap(originalBitmap, (int) croppedBitmapData.left, (int) croppedBitmapData.top, croppedBitmapWidth, croppedBitmapHeight);e1cerunOnUiThread(new Runnable() {@Overridepublic void run() {dlg.dismiss();hasCut = true;choiceView.setImageBitmap(bitmap);}});}}).start();}break;case R.id.btn_modify_process:selectImageCut();break;case R.id.btn_save_process:if (hasCut){String s = saveImageToGalleryString(this, ((BitmapDrawable) (choiceView).getDrawable()).getBitmap());Toast.makeText(this, "保存在"+s, Toast.LENGTH_SHORT).show();}else {Toast.makeText(this, "请先扣图", Toast.LENGTH_SHORT).show();}break;}}private Bitmap cupBitmap(Bitmap bitmap,int x,int y,int width,int height){Mat img = new Mat();//缩小图片尺寸// Bitmap bm = Bitmap.createScaledBitmap(bitmap,bitmap.getWidth(),bitmap.getHeight(),true);//bitmap->matUtils.bitmapToMat(bitmap, img);//转成CV_8UC3格式Imgproc.cvtColor(img, img, Imgproc.COLOR_RGBA2RGB);//设置抠图范围的左上角和右下角Rect rect = new Rect(x,y,width,height);//生成遮板Mat firstMask = new Mat();Mat bgModel = new Mat();Mat fgModel = new Mat();Mat source = new Mat(1, 1, CvType.CV_8U, new Scalar(Imgproc.GC_PR_FGD));Imgproc.grabCut(img, firstMask, rect, bgModel, fgModel,5, Imgproc.GC_INIT_WITH_RECT);Core.compare(firstMask, source, firstMask, Core.CMP_EQ);//抠图Mat foreground = new Mat(img.size(), CvType.CV_8UC3, new Scalar(255, 255, 255));img.copyTo(foreground, firstMask);//mat->bitmapBitmap bitmap1 = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888);Utils.matToBitmap(foreground,bitmap1);return bitmap1;}@Overrideprotected void onDestroy() {super.onDestroy();if (dlg != null) {dlg.dismiss();}}//保存在系统图库public static String saveImageToGalleryString(Context context, Bitmap bmp) {// 首先保存图片String storePath = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "dearxy";File appDir = new File(storePath);if (!appDir.exists()) {appDir.mkdir();}String fileName = System.currentTimeMillis() + ".png";File file = new File(appDir, fileName);try {FileOutputStream fos = new FileOutputStream(file);//通过io流的方式来压缩保存图片bmp.compress(Bitmap.CompressFormat.PNG, 100, fos);fos.flush();fos.close();//把文件插入到系统图库//MediaStore.Images.Media.insertImage(context.getContentResolver(), file.getAbsolutePath(), fileName, null);//保存图片后发送广播通知更新数据库Uri uri = Uri.fromFile(file);context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, uri));return file.getPath();} catch (IOException e) {e.printStackTrace();}return null;}}2.xml布局(布局很丑,请忽视):
<?xml version="1.0" encoding="utf-8"?> <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" tools:context="com.anshi.opencvtest.MainActivity"> <ScrollView android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:id="@+id/linear" > <com.anshi.opencvtest.MyCropView android:id="@+id/myCropView" android:layout_width="wrap_content" android:layout_gravity="center" android:layout_height="300dp" android:src="@drawable/src" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" > <Button android:id="@+id/btn_gray_process" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="选取图片"/> <Button android:id="@+id/btn_modify_process" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="剪切"/> <Button android:id="@+id/btn_cut_process" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="抠图"/> <Button android:id="@+id/btn_save_process" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="保存抠图"/> </LinearLayout> <ImageView android:contentDescription="@null" android:id="@+id/croppedImageView" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </LinearLayout> </ScrollView> </RelativeLayout>
3.自定义的裁剪View
import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Paint.Style; import android.graphics.PointF; import android.graphics.RectF; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; import android.widget.Toast; public class MyCropView extends View { // Private Constants /////////////////////////////////////////////////////// private static final float BMP_LEFT = 0f; private static final float BMP_TOP = 20f; private static final float DEFAULT_BORDER_RECT_WIDTH = 200f; private static final float DEFAULT_BORDER_RECT_HEIGHT = 200f; private static final int POS_TOP_LEFT = 0; private static final int POS_TOP_RIGHT = 1; private static final int POS_BOTTOM_LEFT = 2; private static final int POS_BOTTOM_RIGHT = 3; private static final int POS_TOP = 4; private static final int POS_BOTTOM = 5; private static final int POS_LEFT = 6; private static final int POS_RIGHT = 7; private static final int POS_CENTER = 8; // this constant would be best to use event number private static final float BORDER_LINE_WIDTH = 6f; private static final float BORDER_CORNER_LENGTH = 30f; private static final float TOUCH_FIELD = 10f; // Member Variables //////////////////////////////////////////////////////// private String mBmpPath; private Bitmap mBmpToCrop; private RectF mBmpBound; private Paint mBmpPaint; private Paint mBorderPaint;// 裁剪区边框 private Paint mGuidelinePaint; private Paint mCornerPaint; private Paint mBgPaint; private RectF mDefaultBorderBound; private RectF mBorderBound; private PointF mLastPoint = new PointF(); private float mBorderWidth; private float mBorderHeight; private int touchPos; // Constructors //////////////////////////////////////////////////////////// public MyCropView(Context context) { super(context); // TODO Auto-generated constructor stub init(context); } public MyCropView(Context context, AttributeSet attrs) { super(context, attrs); init(context); } // View Methods //////////////////////////////////////////////////////////// @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { // TODO Auto-generated method stub // super.onSizeChanged(w, h, oldw, oldh); } @Override protected void onDraw(Canvas canvas) { // TODO Auto-generated method stub // super.onDraw(canvas); if (mBmpPath != null) { canvas.drawBitmap(mBmpToCrop, null, mBmpBound, mBmpPaint); canvas.drawRect(mBorderBound.left, mBorderBound.top, mBorderBound.right, mBorderBound.bottom, mBorderPaint); drawGuidlines(canvas); drawBackground(canvas); } } @Override public boolean onTouchEvent(MotionEvent event) { // TODO Auto-generated method stub // super.onTouchEvent(event); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: setLastPosition(event); getParent().requestDisallowInterceptTouchEvent(true); // onActionDown(event.getX(), event.getY()); touchPos = detectTouchPosition(event.getX(), event.getY()); break; case MotionEvent.ACTION_MOVE: onActionMove(event.getX(), event.getY()); setLastPosition(event); break; case MotionEvent.ACTION_UP: break; } return true; } // Public Methods ////////////////////////////////////////////////////////// public String getBmpPath() { return mBmpPath; } public void setBmpPath(String picPath) { this.mBmpPath = picPath; setBmp(); } public RectF getCroppedBitmapData(){ return mBorderBound; } public int getCroppedBitmapWidth(){ return (int) mBorderWidth; } public int getCroppedBitmapHeight(){ return (int) mBorderHeight; } public Bitmap getCroppedImage() { // 先不考虑图片被压缩的情况 就当作现在的图片就是1:1的 Bitmap bitmap = null; try { bitmap = Bitmap.createBitmap(mBmpToCrop, (int) mBorderBound.left, (int) mBorderBound.top, (int) mBorderWidth, (int) mBorderHeight); }catch (Exception e){ Toast.makeText(getContext(), "图片格式无法剪切", Toast.LENGTH_SHORT).show(); e.printStackTrace(); } return bitmap; } // Private Methods ///////////////////////////////////////////////////////// private void init(Context context) { mBmpPaint = new Paint(); // 以下是抗锯齿 mBmpPaint.setAntiAlias(true);// 防止边缘的锯齿 mBmpPaint.setFilterBitmap(true);// 对位图进行滤波处理 mBorderPaint = new Paint(); mBorderPaint.setStyle(Style.STROKE); mBorderPaint.setColor(Color.parseColor("#AAFFFFFF")); mBorderPaint.setStrokeWidth(BORDER_LINE_WIDTH); mGuidelinePaint = new Paint(); mGuidelinePaint.setColor(Color.parseColor("#AAFFFFFF")); mGuidelinePaint.setStrokeWidth(1f); mCornerPaint = new Paint(); mBgPaint = new Paint(); mBgPaint.setColor(Color.parseColor("#B0000000")); mBgPaint.setAlpha(150); } private void setBmp() { mBmpToCrop = BitmapFactory.decodeFile(mBmpPath); mBmpBound = new RectF(); mBmpBound.left = BMP_LEFT; mBmpBound.top = BMP_TOP; mBmpBound.right = mBmpBound.left + mBmpToCrop.getWidth(); mBmpBound.bottom = mBmpBound.top + mBmpToCrop.getHeight(); // 使裁剪框一开始出现在图片的中心位置 mDefaultBorderBound = new RectF(); mDefaultBorderBound.left = (mBmpBound.left + mBmpBound.right - DEFAULT_BORDER_RECT_WIDTH) / 2; mDefaultBorderBound.top = (mBmpBound.top + mBmpBound.bottom - DEFAULT_BORDER_RECT_HEIGHT) / 2; mDefaultBorderBound.right = mDefaultBorderBound.left + DEFAULT_BORDER_RECT_WIDTH; mDefaultBorderBound.bottom = mDefaultBorderBound.top + DEFAULT_BORDER_RECT_HEIGHT; mBorderBound = new RectF(); mBorderBound.left = mDefaultBorderBound.left; mBorderBound.top = mDefaultBorderBound.top; mBorderBound.right = mDefaultBorderBound.right; mBorderBound.bottom = mDefaultBorderBound.bottom; getBorderEdgeLength(); invalidate(); } private void drawBackground(Canvas canvas) { /*- ------------------------------------- | top | ------------------------------------- | | | |<——————————mBmpBound | | | | | left | | right | | | | | | | <─┼───────┼────mBorderBound ------------------------------------- | bottom | ------------------------------------- */ // Draw "top", "bottom", "left", then "right" quadrants. // because the border line width is larger than 1f, in order to draw a complete border rect , // i have to change zhe rect coordinate to draw float delta = BORDER_LINE_WIDTH / 2; float left = mBorderBound.left - delta; float top = mBorderBound.top - delta; float right = mBorderBound.right + delta; float bottom = mBorderBound.bottom + delta; // -------------------------------------------------------------------------------移动到上下两端会多出来阴影 canvas.drawRect(mBmpBound.left, mBmpBound.top, mBmpBound.right, top, mBgPaint); canvas.drawRect(mBmpBound.left, bottom, mBmpBound.right, mBmpBound.bottom, mBgPaint); canvas.drawRect(mBmpBound.left, top, left, bottom, mBgPaint); canvas.drawRect(right, top, mBmpBound.right, bottom, mBgPaint); } // 画裁剪区域中间的参考线 private void drawGuidlines(Canvas canvas) { // Draw vertical guidelines. final float oneThirdCropWidth = mBorderBound.width() / 3; final float x1 = mBorderBound.left + oneThirdCropWidth; canvas.drawLine(x1, mBorderBound.top, x1, mBorderBound.bottom, mGuidelinePaint); final float x2 = mBorderBound.right - oneThirdCropWidth; canvas.drawLine(x2, mBorderBound.top, x2, mBorderBound.bottom, mGuidelinePaint); // Draw horizontal guidelines. final float oneThirdCropHeight = mBorderBound.height() / 3; final float y1 = mBorderBound.top + oneThirdCropHeight; canvas.drawLine(mBorderBound.left, y1, mBorderBound.right, y1, mGuidelinePaint); final float y2 = mBorderBound.bottom - oneThirdCropHeight; canvas.drawLine(mBorderBound.left, y2, mBorderBound.right, y2, mGuidelinePaint); } private void onActionDown(float x, float y) { } private void onActionMove(float x, float y) { float deltaX = x - mLastPoint.x; float deltaY = y - mLastPoint.y; // 这里先不考虑裁剪框放最大的情况 switch (touchPos) { case POS_CENTER: mBorderBound.left += deltaX; // fix border position if (mBorderBound.left < mBmpBound.left) mBorderBound.left = mBmpBound.left; if (mBorderBound.left > mBmpBound.right - mBorderWidth) mBorderBound.left = mBmpBound.right - mBorderWidth; mBorderBound.top += deltaY; if (mBorderBound.top < mBmpBound.top) mBorderBound.top = mBmpBound.top; if (mBorderBound.top > mBmpBound.bottom - mBorderHeight) mBorderBound.top = mBmpBound.bottom - mBorderHeight; mBorderBound.right = mBorderBound.left + mBorderWidth; mBorderBound.bottom = mBorderBound.top + mBorderHeight; break; case POS_TOP: resetTop(deltaY); break; case POS_BOTTOM: resetBottom(deltaY); break; case POS_LEFT: resetLeft(deltaX); break; case POS_RIGHT: resetRight(deltaX); break; case POS_TOP_LEFT: resetTop(deltaY); resetLeft(deltaX); break; case POS_TOP_RIGHT: resetTop(deltaY); resetRight(deltaX); break; case POS_BOTTOM_LEFT: resetBottom(deltaY); resetLeft(deltaX); break; case POS_BOTTOM_RIGHT: resetBottom(deltaY); resetRight(deltaX); break; default: break; } invalidate(); } private void onActionUp(float x, float y) { } private int detectTouchPosition(float x, float y) { if (x > mBorderBound.left + TOUCH_FIELD && x < mBorderBound.right - TOUCH_FIELD && y > mBorderBound.top + TOUCH_FIELD && y < mBorderBound.bottom - TOUCH_FIELD) return POS_CENTER; if (x > mBorderBound.left + BORDER_CORNER_LENGTH && x < mBorderBound.right - BORDER_CORNER_LENGTH) { if (y > mBorderBound.top - TOUCH_FIELD && y < mBorderBound.top + TOUCH_FIELD) return POS_TOP; if (y > mBorderBound.bottom - TOUCH_FIELD && y < mBorderBound.bottom + TOUCH_FIELD) return POS_BOTTOM; } if (y > mBorderBound.top + BORDER_CORNER_LENGTH && y < mBorderBound.bottom - BORDER_CORNER_LENGTH) { if (x > mBorderBound.left - TOUCH_FIELD && x < mBorderBound.left + TOUCH_FIELD) return POS_LEFT; if (x > mBorderBound.right - TOUCH_FIELD && x < mBorderBound.right + TOUCH_FIELD) return POS_RIGHT; } // 前面的逻辑已经排除掉了几种情况 所以后面的 ┏ ┓ ┗ ┛ 边角就按照所占区域的方形来判断就可以了 if (x > mBorderBound.left - TOUCH_FIELD && x < mBorderBound.left + BORDER_CORNER_LENGTH) { if (y > mBorderBound.top - TOUCH_FIELD && y < mBorderBound.top + BORDER_CORNER_LENGTH) return POS_TOP_LEFT; if (y > mBorderBound.bottom - BORDER_CORNER_LENGTH && y < mBorderBound.bottom + TOUCH_FIELD) return POS_BOTTOM_LEFT; } if (x > mBorderBound.right - BORDER_CORNER_LENGTH && x < mBorderBound.right + TOUCH_FIELD) { if (y > mBorderBound.top - TOUCH_FIELD && y < mBorderBound.top + BORDER_CORNER_LENGTH) return POS_TOP_RIGHT; if (y > mBorderBound.bottom - BORDER_CORNER_LENGTH && y < mBorderBound.bottom + TOUCH_FIELD) return POS_BOTTOM_RIGHT; } return -1; } private void setLastPosition(MotionEvent event) { mLastPoint.x = event.getX(); mLastPoint.y = event.getY(); } private void getBorderEdgeLength() { mBorderWidth = mBorderBound.width(); mBorderHeight = mBorderBound.height(); } private void getBorderEdgeWidth() { mBorderWidth = mBorderBound.width(); } private void getBorderEdgeHeight() { mBorderHeight = mBorderBound.height(); } private void resetLeft(float delta) { mBorderBound.left += delta; getBorderEdgeWidth(); fixBorderLeft(); } private void resetTop(float delta) { mBorderBound.top += delta; getBorderEdgeHeight(); fixBorderTop(); } private void resetRight(float delta) { mBorderBound.right += delta; getBorderEdgeWidth(); fixBorderRight(); } private void resetBottom(float delta) { mBorderBound.bottom += delta; getBorderEdgeHeight(); fixBorderBottom(); } private void fixBorderLeft() { // fix left if (mBorderBound.left < mBmpBound.left) mBorderBound.left = mBmpBound.left; if (mBorderWidth < 2 * BORDER_CORNER_LENGTH) mBorderBound.left = mBorderBound.right - 2 * BORDER_CORNER_LENGTH; } private void fixBorderTop() { // fix top if (mBorderBound.top < mBmpBound.top) mBorderBound.top = mBmpBound.top; if (mBorderHeight < 2 * BORDER_CORNER_LENGTH) mBorderBound.top = mBorderBound.bottom - 2 * BORDER_CORNER_LENGTH; } private void fixBorderRight() { // fix right if (mBorderBound.right > mBmpBound.right) mBorderBound.right = mBmpBound.right; if (mBorderWidth < 2 * BORDER_CORNER_LENGTH) mBorderBound.right = mBorderBound.left + 2 * BORDER_CORNER_LENGTH; } private void fixBorderBottom() { // fix bottom if (mBorderBound.bottom > mBmpBound.bottom) mBorderBound.bottom = mBmpBound.bottom; if (mBorderHeight < 2 * BORDER_CORNER_LENGTH) mBorderBound.bottom = mBorderBound.top + 2 * BORDER_CORNER_LENGTH; } }end...............好了,就这些了,快去试试把!
相关文章推荐
- 在android 上,使用Opencv3.0实现图像无缝拼接,Fast查找特征点,BruteForce进行匹配
- Android(安卓)开发通过NDK调用JNI,使用opencv做本地c++代码开发配置方法实现边缘检测代码(2)
- Android使用OpenCV实现「人脸检测」和「人脸识别」
- Android中使用Opencv自带JavaCameraView实现高帧率竖屏显示
- android端使用openCV实现车牌检测
- 【Android】Android使用OpenCV实现人脸识别(OpenCV+JavaCV)
- OpenCV4Android开发实录(2): 使用OpenCV3.4.1库实现人脸检测
- 4000 Android自定义View--使用NestScrolling机制实现一个上下滑动退出Layout
- Android使用OpenCV实现「人脸检测」和「人脸识别」
- Android 使用OPENCV实现图像实时对比
- Android下使用jni实现基于opencv与dlib的68关键点检测
- Android Studio 使用 java 通过 OpenCV4Android 实现 Hello OpenCV
- android端使用openCV与深度学习实现车牌识别
- Android使用OpenCV CamShift实现目标追踪
- OpenCV4Android在2.x版本中不使用OpenCVManager以及编译SIFT算法实现
- 使用线程创建的三种方法实现j2me联网(PS:我想做android!NND!)
- 使用Android自带Gallery组件实现CoverFlow,源码+解析
- Android使用SharedPreferences实现数据存储
- 使用android隐藏api实现亮度调节
- Android GPS 定位的实现(2-1) 使用Google地图