zoukankan      html  css  js  c++  java
  • opencv在手机上实现照片背景虚化

    概述

    使用androidstudio开发,在手机上实现照片背景虚化

    详细

    一、准备工作

    1、需要下载安装androidstudio和相关JDK,这两者下载安装和普通软件一样,

    JDK:

    http://www.oracle.com/technetwork/java/javase/downloads/index.html

    androidstuido:

    http://www.android-studio.org/

    2、本例子在安卓手机上开发图像美化效果,用以在手机相机上实现类似高羰数码相机的背景虚化特效

    3.软件下载安装配置完成后,下载本实例解压,打开androidstudio,选择FILE-》OPEN菜单,在弹出的对话中选择实例解压的位置,打开就行了

    二、程序实现

    1、主程序包含一个源码主文件MainActivity一个布局文件layout及相当菜单资源

    图片.png

    2、实现思路怎样

    要使用软件技术精确的背景虚化,需要经过三个步骤:

    一是选定区域,根据远区使用抠图技术实现前背景分离

    二对背景根据需要使用高斯或者平均值等模糊方法处理

    三把处理后的背景和前景合并

    3、具体设计到哪些代码

    import android.app.Activity;
    import android.app.ProgressDialog;
    import android.content.Intent;
    import android.database.Cursor;
    import android.graphics.Bitmap;
    import android.graphics.BitmapFactory;
    import android.graphics.Canvas;
    import android.graphics.Paint;
    import android.graphics.RectF;
    import android.graphics.drawable.BitmapDrawable;
    import android.net.Uri;
    import android.os.AsyncTask;
    import android.os.Bundle;
    import android.provider.MediaStore;
    import android.util.Log;
    import android.view.Menu;
    import android.view.MenuItem;
    import android.view.MotionEvent;
    import android.view.View;
    import android.widget.ImageView;
    
    import org.opencv.android.BaseLoaderCallback;
    import org.opencv.android.LoaderCallbackInterface;
    import org.opencv.android.OpenCVLoader;
    import org.opencv.core.Core;
    import org.opencv.core.CvType;
    import org.opencv.core.Mat;
    import org.opencv.core.Point;
    import org.opencv.core.Rect;
    import org.opencv.core.Scalar;
    import org.opencv.core.Size;
    import org.opencv.imgcodecs.Imgcodecs;
    import org.opencv.imgproc.Imgproc;
    
    
    public class MainActivity extends Activity {
    
        static final int REQUEST_OPEN_IMAGE = 1;
    
        String mCurrentPhotoPath;
        Bitmap mBitmap;
        ImageView mImageView;
        int touchCount = 0;
        Point tl;
        Point br;
        boolean targetChose = false;
        ProgressDialog dlg;
        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);
            }
        }
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            mImageView = (ImageView) findViewById(R.id.imgDisplay);
            dlg = new ProgressDialog(this);
            tl = new Point();
            br = new Point();
            // if (!OpenCVLoader.initDebug()) {
            // Handle initialization error
            //}
        }
    
        @Override
        public boolean onCreateOptionsMenu(Menu menu) {
            // Inflate the menu; this adds items to the action bar if it is present.
            getMenuInflater().inflate(R.menu.menu_main, menu);
            return true;
        }
        int scaleFactor = 1;
        private void setPic() {
            int targetW = 720;//mImageView.getWidth();
            int targetH = 1128;//mImageView.getHeight();
            Log.i(">>>>>", "targetW="+targetW);
            Log.i(">>>>>", "targetH=" + targetH);
            BitmapFactory.Options bmOptions = new BitmapFactory.Options();
            bmOptions.inJustDecodeBounds = true;
            BitmapFactory.decodeFile(mCurrentPhotoPath, bmOptions);
            int photoW = bmOptions.outWidth;
            int photoH = bmOptions.outHeight;
            Log.i(">>>>>", "photoW="+photoW);
            Log.i(">>>>>", "photoH=" + photoH);
    
            scaleFactor = Math.max(photoW / targetW, photoH / targetH)+1;
            Log.i(">>>>>", "photoW / targetW="+(photoW / targetW));
            Log.i(">>>>>", "photoH / targetH="+(photoH / targetH));
    
            bmOptions.inJustDecodeBounds = false;
            bmOptions.inSampleSize = scaleFactor;
            bmOptions.inPurgeable = true;
    
            mBitmap = BitmapFactory.decodeFile(mCurrentPhotoPath, bmOptions);
            mImageView.setImageBitmap(mBitmap);
            Log.i(">>>>>", "mBitmap.getWidth()="+mBitmap.getWidth());
            Log.i(">>>>>", "mBitmap.getHeight()=" + mBitmap.getHeight());
        }
    
        @Override
        protected 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;
            }
        }
    
        @Override
        public boolean onOptionsItemSelected(MenuItem item) {
            int id = item.getItemId();
    
            switch (id) {
                case R.id.action_open_img:
                    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);
                    return true;
                case R.id.action_choose_target:
    
                    if (mCurrentPhotoPath != null)
                        targetChose = false;
                    mImageView.setOnTouchListener(new View.OnTouchListener() {
    
                        @Override
                        public boolean onTouch(View v, MotionEvent event) {
                            int cx = (mImageView.getWidth()-mBitmap.getWidth())/2;
                            int cy = (mImageView.getHeight()-mBitmap.getHeight())/2;
                            if (event.getAction() == MotionEvent.ACTION_DOWN) {
                                if (touchCount == 0) {
                                    tl.x = event.getX();//300;//
                                    tl.y = event.getY();//300;//
                                    touchCount++;
                                }
                                else if (touchCount == 1) {
                                    br.x = event.getX();//1100;//
                                    br.y = event.getY();//1200;//
    
                                    Paint rectPaint = new Paint();
                                    rectPaint.setARGB(255, 255, 0, 0);
                                    rectPaint.setStyle(Paint.Style.STROKE);
                                    rectPaint.setStrokeWidth(3);
                                    Bitmap tmpBm = Bitmap.createBitmap(mBitmap.getWidth(),
                                            mBitmap.getHeight(), Bitmap.Config.RGB_565);
                                    Canvas tmpCanvas = new Canvas(tmpBm);
    
                                    tmpCanvas.drawBitmap(mBitmap, 0, 0, null);
                                    tmpCanvas.drawRect(new RectF((float) tl.x, (float) tl.y, (float) br.x, (float) br.y),
                                            rectPaint);
                                    mImageView.setImageDrawable(new BitmapDrawable(getResources(), tmpBm));
    
                                    targetChose = true;
                                    touchCount = 0;
                                    mImageView.setOnTouchListener(null);
                                }
                            }
    
                            return true;
                        }
                    });
    
                    return true;
                case R.id.action_cut_image:
                    if (mCurrentPhotoPath != null && targetChose) {
                        new ProcessImageTask().execute();
                        targetChose = false;
                    }
                    return true;
            }
    
            return super.onOptionsItemSelected(item);
        }
    
        private class ProcessImageTask extends AsyncTask<Integer, Integer, Integer> {
            Mat img;
            Mat foreground;
            @Override
            protected void onPreExecute() {
                super.onPreExecute();
                dlg.setMessage("Processing Image...");
                dlg.setCancelable(false);
                dlg.setIndeterminate(true);
                dlg.show();
            }
    
            @Override
            protected Integer doInBackground(Integer... params) {
                //Mat img = new Mat(mBitmap.getHeight(), mBitmap.getHeight(), CvType.CV_8UC3);
                //Utils.bitmapToMat(mBitmap, img);
                long ll = System.currentTimeMillis();
                Log.i(">>>>>", "start="+ll);
                img = Imgcodecs.imread(mCurrentPhotoPath);
                Imgproc.resize(img, img, new Size(img.cols()/scaleFactor, img.rows()/scaleFactor));
                Log.i(">>>>>", "11111=" + System.currentTimeMillis()+"@@@@@"+(System.currentTimeMillis()-ll));
                Mat background = new Mat(img.size(), CvType.CV_8UC3,
                        new Scalar(255, 255, 255));
    
                Mat firstMask = new Mat();
                Mat bgModel = new Mat();
                Mat fgModel = new Mat();
                Mat mask;
                Mat source = new Mat(1, 1, CvType.CV_8U, new Scalar(Imgproc.GC_PR_FGD));
                Mat dst = new Mat();
                Rect rect = new Rect(tl, br);
                Log.i(">>>>>", "22222="+System.currentTimeMillis()+"@@@@@"+(System.currentTimeMillis()-ll));
                Imgproc.grabCut(img, firstMask, rect, bgModel, fgModel,
                        1, Imgproc.GC_INIT_WITH_RECT);
                Log.i(">>>>>", "33333=" + System.currentTimeMillis() + "@@@@@" + (System.currentTimeMillis() - ll));
                Core.compare(firstMask, source, firstMask, Core.CMP_EQ);
                Log.i(">>>>>", "44444=" + System.currentTimeMillis() + "@@@@@" + (System.currentTimeMillis() - ll));
                foreground = new Mat(img.size(), CvType.CV_8UC3,
                        new Scalar(255, 255, 255));
                /////
                img.copyTo(foreground);
                Imgproc.blur(foreground, foreground, new Size(20, 20));
                Log.i(">>>>>", "55555=" + System.currentTimeMillis()+"@@@@@"+(System.currentTimeMillis()-ll));
                /////
                img.copyTo(foreground, firstMask);
                Log.i(">>>>>", "66666=" + System.currentTimeMillis()+"@@@@@"+(System.currentTimeMillis()-ll));
    
                firstMask.release();
                source.release();
                bgModel.release();
                fgModel.release();
    
                Imgcodecs.imwrite(mCurrentPhotoPath + ".png", foreground);
    
                return 0;
            }
    
            @Override
            protected void onPostExecute(Integer result) {
                super.onPostExecute(result);
    
                Bitmap jpg = BitmapFactory
                        .decodeFile(mCurrentPhotoPath + ".png");
    
                mImageView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
                mImageView.setAdjustViewBounds(true);
                mImageView.setPadding(2, 2, 2, 2);
                mImageView.setImageBitmap(jpg);
                mImageView.invalidate();
    
    
                dlg.dismiss();
            }
        }
    }

    4、配置文件说明

    三、运行效果

    运行,右键项目:Run as -》Android Application

    1、运行时的截图

    http://img.blog.csdn.net/20170712095836383?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY25ibG9nZXI=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center

    http://img.blog.csdn.net/20170712095849359?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY25ibG9nZXI=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center

    四、其他补充

    1、Imgproc.grab分割前景效果比较好,但速度比较慢,如果是确认是固定的比如人脸,水果,植物,可以使用其他OPENCV提代的其他分割方法以加快速度

    2.有关模糊,可以根据需要选择合适的模糊算法,比如高斯,比如运动模糊等

    注:本文著作权归作者,由demo大师发表,拒绝转载,转载需要作者授权

  • 相关阅读:
    springAOP实现原理
    cglib用法
    git 用法
    java基础算法之快速排序
    记一次与a标签相遇的小事
    java设计模式之建造者模式
    HashMap源码分析
    Linux下安装nginx
    java设计模式之策略模式
    java设计模式之中介者模式
  • 原文地址:https://www.cnblogs.com/demodashi/p/8481563.html
Copyright © 2011-2022 走看看