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、具体设计到哪些代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
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、运行时的截图

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

//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大师发表,拒绝转载,转载需要作者授权

posted on   demo例子集  阅读(1634)  评论(0编辑  收藏  举报

(评论功能已被禁用)
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· 使用C#创建一个MCP客户端
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· Windows编程----内核对象竟然如此简单?

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5
点击右上角即可分享
微信分享提示