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) {@Overridepublic 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->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));//这是实现抠图的重点,难点在于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->bitmapBitmap 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) {@Overridepublic void onManagerConnected(int status) {switch (status) {case LoaderCallbackInterface.SUCCESS:{Log.i(TAG, "OpenCV loaded successfully");} break;default:{super.onManagerConnected(status);} break;}}};@Overridepublic 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);runOnUiThread(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"?>
<RelativeLayoutxmlns: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"><ScrollViewandroid:layout_width="match_parent"android:layout_height="match_parent"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="vertical"android:id="@+id/linear"><com.anshi.opencvtest.MyCropViewandroid:id="@+id/myCropView"android:layout_width="wrap_content"android:layout_gravity="center"android:layout_height="300dp"android:src="@drawable/src" /><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"><Buttonandroid:id="@+id/btn_gray_process"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="选取图片"/><Buttonandroid:id="@+id/btn_modify_process"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="剪切"/><Buttonandroid:id="@+id/btn_cut_process"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="抠图"/><Buttonandroid:id="@+id/btn_save_process"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="保存抠图"/></LinearLayout><ImageViewandroid: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 numberprivate 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 stubinit(context);}public MyCropView(Context context, AttributeSet attrs) {super(context, attrs);init(context);}// View Methods @Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {// TODO Auto-generated method stub// super.onSizeChanged(w, h, oldw, oldh);}@Overrideprotected 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);}}@Overridepublic 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 drawfloat 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 positionif (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 leftif (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 topif (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 rightif (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 bottomif (mBorderBound.bottom > mBmpBound.bottom)mBorderBound.bottom = mBmpBound.bottom;if (mBorderHeight < 2 * BORDER_CORNER_LENGTH)mBorderBound.bottom = mBorderBound.top + 2 * BORDER_CORNER_LENGTH;}
}

end...............好了,就这些了,快去试试把!

												

Android 使用opencv实现抠图相关推荐

  1. 搭建Android+QT+OpenCV环境,实现“单色图片着色”效果

    OpenCV是我们大家非常熟悉的图像处理开源类库:在其新版本将原本在Contrib分库中的DNN模块融合到了主库中,并且更新了相应文档.这样我们就能够非常方便地利用OpenCV实现一些属于DeepLe ...

  2. Android Studio+OpenCV 识别身份证号码---识别身份证号码

    上一章使用CLion+OpenCV对身份证号码进行了检测,经过检测我们能拿到身份证号码区域的照片,现在我们对上一章拿到的图片中的数字进行识别 上一章链接:CLion+OpenCV 识别身份证号码--- ...

  3. Android之OpenCv简单人脸识别功能(Bitmap)

    Android之OpenCv简单人脸识别功能 OpenCv的下载 下载地址 - https://opencv.org/releases/ doc 文档目录 samples 示例代码 sdk 编译后的动 ...

  4. 基于Opencv的抠图

    参考   基于Opencv的抠图 - 云+社区 - 腾讯云 举一个例子,我想要把一张图片中的某一个东西抠出来.如下图: step1:加载图片,转成灰度图. image = cv2.imread(&qu ...

  5. 基于Android和OpenCV的答题卡识别软件

    基于Android和OpenCV的答题卡识别软件 1. 软件介绍 设计目标是可以添加不同的考试,在不同考试下可以设置模板,包括题目数量.答题卡样式.每题分值以及每题答案:扫描结果按列表显示,并讲识别出 ...

  6. Android版OpenCV图像处理技术亲自验证[三]之斑点检测ColorBlobDetector

    Android版OpenCV图像处理技术亲自验证[二]之斑点检测ColorBlobDetector 程序之美 前言 主体 运行效果 构建过程 核心代码 所遇问题 结束语 程序之美 前言 OpenCV是 ...

  7. 学习笔记—android实现opencv人脸检测

    1.导入opencv库 在Android studio导入OpenCV配置使用中有详细说明 2.添加文件 Manifest 的设置权限,主要是对摄像头添加权限 <?xml version=&qu ...

  8. Android 使用opencv实现单一背景抠图并且替换背景

    支持技术分享,转载或复制,请指出文章来源 此博客作者为Jack__0023 效果如下 原图 背景图片 处理效果图片 1.简介 1-1.使用 Opencv 实现单一背景的自动抠图功能,用 Opencv ...

  9. python抠图_python和opencv实现抠图

    本文实例为大家分享了python实现抠图的具体代码,供大家参考,具体内容如下 其中使用了opencv中的grabcut方法 直接上代码 # encoding:utf-8 # 图像提取 # create ...

最新文章

  1. 云计算自动化对于虚拟化环境意味着什么?
  2. 单文档应用程序弹出新对话框_简介——文档
  3. apache php 升级5.6,升级 apache2.4.41-php5.6.40
  4. 正则不能全为某个值_TensorFlow学习Program1——补充附录(7)线性回归、逻辑回归与正则化...
  5. kubernetes(三)k8s中通信和Service
  6. 在线VS Code阅读源码神器 github1s
  7. Windows Phone 实用开发技巧(18):使用SystemTray显示全局消息提醒
  8. 循序渐进Oracle:数据库的字符集和字符集文件
  9. 推荐一款图片轮换jQuery插件
  10. jQuery插件(多级菜单)
  11. 算法复习——带修改莫队(bzoj2453)
  12. redis中集群的故障恢复
  13. 拓端tecdat|R语言中的block Gibbs吉布斯采样贝叶斯多元线性回归
  14. python安装哪个版本好啊_Python 的版本选择与安装细节
  15. 苹果乔布斯的成功启示,看完要被惊醒!
  16. Unity2021 Inventory(背包)系统学习记录
  17. 【Linux】怎么理解进程
  18. 回复整理 080307
  19. 华为Huawei服务器IBMC默认用户密码
  20. opencv 读取一帧时间及imshow耗时

热门文章

  1. 密码学:商用密码应用(智能密码钥匙)
  2. 通过adb命令获取Android手机的IP地址
  3. ios 原生语音识别,百度翻译API使用,原生文字转语音播报
  4. OTT安卓电视盒系统发展的3种模式
  5. 开源的文章又被培训机构“BP”了,这次不忍了
  6. netty编解码器注意事项及粘包和拆包解决方案
  7. Java8 Streams Collectors 使用
  8. 情人节,超赞程序员这样表达自己的爱意~
  9. selenium 后续来啦 ! ! !
  10. 手机版天气预报代码html代码大全,天气预报代码大全(The weather code).doc