Android使用OpenCV和FFMpeg的简单方法-开源项目javacv的使用

转载 2012年11月12日 16:43:01

转自:http://doandroid.info/android%E4%BD%BF%E7%94%A8opencv%E5%92%8Cffmpeg%E7%9A%84%E7%AE%80%E5%8D%95%E6%96%B9%E6%B3%95-%E5%BC%80%E6%BA%90%E9%A1%B9%E7%9B%AEjavacv%E7%9A%84%E4%BD%BF%E7%94%A8/

首先感谢javacv开源项目的工作组.

0 使用说明

JavaCV first provides wrappers to commonly used libraries by researchers in the field of computer vision: OpenCV, FFmpeg, libdc1394, PGR FlyCapture, OpenKinect, videoInput, and ARToolKitPlus. The following classes, found under the com.googlecode.javacv.cpp package namespace, expose their complete APIs: opencv_core, opencv_imgproc, opencv_video, opencv_flann, opencv_features2d, opencv_calib3d, opencv_objdetect, opencv_highgui, opencv_legacy, opencv_ml, opencv_contrib, avutil, avcodec, avformat, avdevice, avfilter, postproc, swscale, dc1394, PGRFlyCapture, freenect, videoInputLib, and ARToolKitPlus, respectively. Moreover, utility classes make it easy to use their functionality on the Java platform, including Android.

javacv的项目最早是为java平台封装了机器视觉领域的开源库,后提供Android支持。其中的库包含OpenCV, FFmpeg, libdc1394, PGR FlyCapture, OpenKinect, videoInput, and ARToolKitPlus等等。在命名空间com.googlecode.javacv.cpp下包含了所有的类对象。并暴露出了他们完整的API:opencv_legacy, opencv_ml, opencv_contrib, avutil, avcodec, avformat, avdevice, avfilter, postproc, swscale, dc1394, PGRFlyCapture, freenect, videoInputLib, and ARToolKitPlus.工具类的使用使得我们可以非常容易的使用他的功能。

1 Follow the instructions on this page: http://developer.android.com/resources/tutorials/hello-world.html
2 Go to File > New > Folder, select your project as parent folder, type “libs/armeabi” as Folder name, and click Finish.
3 Copy javacpp.jar and javacv.jar in the newly created “libs” folder.
4 Extract directly all the *.so files from javacv-android-arm.jar as well as the ones from OpenCV-2.3.1-android-arm.zip and ffmpeg-0.7.11-android-arm.zip in the newly created “libs/armeabi” folder, without creating any new subdirectories.
5 Navigate to Project > Properties > Java Build Path > Libraries and click “Add JARs…”
6 Select both javacpp.jar and javacv.jar from the newly created “libs” folder.

本文将介绍如何在Android中使用这些库。

1 创建一个Android项目
2 在新建的项目上,右击选择Folder,输入libs/armeabi作为文件夹名称。这里解释一下,我们在使用jni的方式开发Android项目的时候,使用ndk-build编译项目后,一般会自动生成libs/armeabi文件夹,并将我们的库.so或者.a文件在文件夹中生成。本文也是这个目的。后面将会拷贝很多文件到这个目录里面来。
3 在 http://code.google.com/p/javacv/downloads/list 下载几个文件。
3.1 javacv-bin-20120329.zip
3.2 ffmpeg-0.7.11-android-arm.zip
3.3 OpenCV-2.3.1-android-arm.zip
解压所有的文件,并将javacv-bin-20120329.zip中的javacpp.jar和javacv.jar拷贝到刚才建立的/libs目录。
将javacv-bin-20120329.zip目录的javacv-android-arm.jar文件打开,进入最里面的目录,将所有的.so文件拷贝到libs/armeabi目录。
将ffmpeg-0.7.11-android-arm.zip里面的所有.so文件拷贝到libs/armeabi目录。
将OpenCV-2.3.1-android-arm.zip里面的所有.so文件拷贝到libs/armeabi目录。
4 选择Project->Properties->Java Build Path->Libraries,点击Add JARs…并选择libs目录的javacpp.jar 和 javacv.jar文件。

1 文件下载

1.1 javacv-bin-20120329.zip
1.2 ffmpeg-0.7.11-android-arm.zip
1.3 OpenCV-2.3.1-android-arm.zip
2 创建项目
新建一个Android项目。
3 加入lib库文件
将javacv-bin-20120329.zip中的javacpp.jar和javacv.jar拷贝到刚才建立的/libs目录。
将javacv-bin-20120329.zip目录的javacv-android-arm.jar文件打开,进入最里面的目录,将所有的.so文件拷贝到libs/armeabi目录。
将ffmpeg-0.7.11-android-arm.zip里面的所有.so文件拷贝到libs/armeabi目录。
将OpenCV-2.3.1-android-arm.zip里面的所有.so文件拷贝到libs/armeabi目录。

4 编译例子代码FacePreview
本代码在javacv-bin-20120329.zip压缩文件中,进入/javacv-bin/samples/目录,将FacePreview.java加入到刚刚建立项目的src目录。
本代码不需要layout文件。
下面的代码含部分注释:

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
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
/*
 * Copyright (C) 2010,2011,2012 Samuel Audet
 *
 * FacePreview - A fusion of OpenCV's facedetect and Android's CameraPreview samples,
 *               with JavaCV + JavaCPP as the glue in between.
 *
 * This file was based on CameraPreview.java that came with the Samples for 
 * Android SDK API 8, revision 1 and contained the following copyright notice:
 *
 * Copyright (C) 2007 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 *
 * IMPORTANT - Make sure the AndroidManifest.xml file looks like this:
 *
 * <?xml version="1.0" encoding="utf-8"?>
 * <manifest xmlns:android="http://schemas.android.com/apk/res/android"
 *     package="com.googlecode.javacv.facepreview"
 *     android:versionCode="1"
 *     android:versionName="1.0" >
 *     <uses-sdk android:minSdkVersion="4" />
 *     <uses-permission android:name="android.permission.CAMERA" />
 *     <uses-feature android:name="android.hardware.camera" />
 *     <application android:label="@string/app_name">
 *         <activity
 *             android:name="FacePreview"
 *             android:label="@string/app_name"
 *             android:screenOrientation="landscape">
 *             <intent-filter>
 *                 <action android:name="android.intent.action.MAIN" />
 *                 <category android:name="android.intent.category.LAUNCHER" />
 *             </intent-filter>
 *         </activity>
 *     </application>
 * </manifest>
 */


package com.jouhu.opencvffmpeg;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ImageFormat;
import android.graphics.Paint;
import android.hardware.Camera;
import android.hardware.Camera.Size;
import android.os.Bundle;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.FrameLayout;
import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.List;
import com.googlecode.javacpp.Loader;
import com.googlecode.javacv.cpp.opencv_objdetect;

import static com.googlecode.javacv.cpp.opencv_core.*;
import static com.googlecode.javacv.cpp.opencv_imgproc.*;
import static com.googlecode.javacv.cpp.opencv_objdetect.*;
import static com.googlecode.javacv.cpp.opencv_highgui.*;

// ----------------------------------------------------------------------

public class FacePreview extends Activity {
    private FrameLayout layout;
    private FaceView faceView;
    private Preview mPreview;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //设置全屏
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);

        // Hide the window title.
        //隐藏标题栏
        requestWindowFeature(Window.FEATURE_NO_TITLE);

        // Create our Preview view and set it as the content of our activity.
        try {
            //代码创建FrameLayout 对象,并将FaceView加入Layout其中
            layout = new FrameLayout(this);
            faceView = new FaceView(this);
            mPreview = new Preview(this, faceView);
            layout.addView(mPreview);
            layout.addView(faceView);
            setContentView(layout);
        } catch (IOException e) {
            e.printStackTrace();
            new AlertDialog.Builder(this).setMessage(e.getMessage()).create().show();
        }
    }
}

// ----------------------------------------------------------------------
//基于View继承并实现Camera.PreviewCallback接口的FaceView对象
class FaceView extends View implements Camera.PreviewCallback {
    public static final int SUBSAMPLING_FACTOR = 4;

    //定义opencv中的IplImage对象
    private IplImage grayImage;
    //Haar选择子定义
    private CvHaarClassifierCascade classifier;
    //opencv的内存对象定义
    private CvMemStorage storage;
    private CvSeq faces;

    public FaceView(FacePreview context) throws IOException {
        super(context);

        // Load the classifier file from Java resources.
        //加载面部识别haar选择子的xml文件
        File classifierFile = Loader.extractResource(getClass(),
            "/com/jouhu/opencvffmpeg/haarcascade_frontalface_alt.xml",
            context.getCacheDir()"classifier"".xml");
        if (classifierFile == null || classifierFile.length() <= 0) {
            throw new IOException("Could not extract the classifier file from Java resource.");
        }
        //Log.v("FaceView", "1111111111111111111111111111");
        // Preload the opencv_objdetect module to work around a known bug.
        //加载opencv_objdetect.so文件
        Loader.load(opencv_objdetect.class);
        //Log.v("FaceView", "1111111111111111111111111111");
        //创建Haar对象
        classifier = new CvHaarClassifierCascade(cvLoad(classifierFile.getAbsolutePath()));
        //Log.v("FaceView", "1111111111111111111111111111");
        classifierFile.delete();
        if (classifier.isNull()) {
            throw new IOException("Could not load the classifier file.");
        }
        //Log.v("FaceView", "1111111111111111111111111111");
        storage = CvMemStorage.create();
    }

    public void onPreviewFrame(final byte[] data, final Camera camera) {
        try {
            //获取到每帧图像的时候,调用函数processImage对数据进行处理,并将处理后的数据给camera并显示出来
            Camera.Size size = camera.getParameters().getPreviewSize();
            processImage(data, size.width, size.height);
            camera.addCallbackBuffer(data);
        } catch (RuntimeException e) {
            // The camera has probably just been released, ignore.
        }
    }

    protected void processImage(byte[] data, int width, int height) {
        // First, downsample our image and convert it into a grayscale IplImage
        int f = SUBSAMPLING_FACTOR;
        if (grayImage == null || grayImage.width() != width/|| grayImage.height() != height/f) {
            grayImage = IplImage.create(width/f, height/f, IPL_DEPTH_8U, 1);
        }
        int imageWidth  = grayImage.width();
        int imageHeight = grayImage.height();
        int dataStride = f*width;
        int imageStride = grayImage.widthStep();
        ByteBuffer imageBuffer = grayImage.getByteBuffer();
        for (int y = 0; y < imageHeight; y++) {
            int dataLine = y*dataStride;
            int imageLine = y*imageStride;
            for (int x = 0; x < imageWidth; x++) {
                imageBuffer.put(imageLine + x, data[dataLine + f*x]);
            }
        }
        //Haar 脸部检测函数
        faces = cvHaarDetectObjects(grayImage, classifier, storage, 1.13, CV_HAAR_DO_CANNY_PRUNING);
        //重绘 触发onDraw
        postInvalidate();
        cvClearMemStorage(storage);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        Paint paint = new Paint();
        paint.setColor(Color.RED);
        paint.setTextSize(20);

        String s = "FacePreview - This side up.";
        float textWidth = paint.measureText(s);
        canvas.drawText(s, (getWidth()-textWidth)/220, paint);

        if (faces != null) {
            paint.setStrokeWidth(2);
            paint.setStyle(Paint.Style.STROKE);
            float scaleX = (float)getWidth()/grayImage.width();
            float scaleY = (float)getHeight()/grayImage.height();
            int total = faces.total();
            for (int i = 0; i < total; i++) {
                CvRect r = new CvRect(cvGetSeqElem(faces, i));
                int x = r.x(), y = r.y(), w = r.width(), h = r.height();
                canvas.drawRect(x*scaleX, y*scaleY, (x+w)*scaleX, (y+h)*scaleY, paint);
            }
        }
    }
}

// ----------------------------------------------------------------------

class Preview extends SurfaceView implements SurfaceHolder.Callback {
    SurfaceHolder mHolder;
    Camera mCamera;
    Camera.PreviewCallback previewCallback;

    Preview(Context context, Camera.PreviewCallback previewCallback) {
        super(context);
        this.previewCallback = previewCallback;

        // Install a SurfaceHolder.Callback so we get notified when the
        // underlying surface is created and destroyed.
        mHolder = getHolder();
        mHolder.addCallback(this);
        mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    }

    public void surfaceCreated(SurfaceHolder holder) {
        // The Surface has been created, acquire the camera and tell it where
        // to draw.
        mCamera = Camera.open();
        try {
           mCamera.setPreviewDisplay(holder);
        } catch (IOException exception) {
            mCamera.release();
            mCamera = null;
            // TODO: add more exception handling logic here
        }
    }

    public void surfaceDestroyed(SurfaceHolder holder) {
        // Surface will be destroyed when we return, so stop the preview.
        // Because the CameraDevice object is not a shared resource, it's very
        // important to release it when the activity is paused.
        mCamera.stopPreview();
        mCamera.release();
        mCamera = null;
    }


    private Size getOptimalPreviewSize(List<Size> sizes, int w, int h) {
        final double ASPECT_TOLERANCE = 0.05;
        double targetRatio = (double) w / h;
        if (sizes == null) return null;

        Size optimalSize = null;
        double minDiff = Double.MAX_VALUE;

        int targetHeight = h;

        // Try to find an size match aspect ratio and size
        for (Size size : sizes) {
            double ratio = (double) size.width / size.height;
            if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue;
            if (Math.abs(size.height - targetHeight) < minDiff) {
                optimalSize = size;
                minDiff = Math.abs(size.height - targetHeight);
            }
        }

        // Cannot find the one match the aspect ratio, ignore the requirement
        if (optimalSize == null) {
            minDiff = Double.MAX_VALUE;
            for (Size size : sizes) {
                if (Math.abs(size.height - targetHeight) < minDiff) {
                    optimalSize = size;
                    minDiff = Math.abs(size.height - targetHeight);
                }
            }
        }
        return optimalSize;
    }

    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
        // Now that the size is known, set up the camera parameters and begin
        // the preview.
        Camera.Parameters parameters = mCamera.getParameters();

        List<Size> sizes = parameters.getSupportedPreviewSizes();
        Size optimalSize = getOptimalPreviewSize(sizes, w, h);
        parameters.setPreviewSize(optimalSize.width, optimalSize.height);

        mCamera.setParameters(parameters);
        if (previewCallback != null) {
            mCamera.setPreviewCallbackWithBuffer(previewCallback);
            Camera.Size size = parameters.getPreviewSize();
            byte[] data = new byte[size.width*size.height*
                    ImageFormat.getBitsPerPixel(parameters.getPreviewFormat())/8];
            mCamera.addCallbackBuffer(data);
        }
        mCamera.startPreview();
    }

}

5 注意事项
5.1 项目里面需要一个haarcascade_frontalface_alt.xml文件,请务必放到src目录,跟FacePreview.java在同一个目录下,如果找不到,可以下载本项目。包含了这个代码。
5.2 本代码使用的javacv版本为2012年4月11日版本,请随时关注javacv的代码更新。
5.3 务必加入权限设置,如果不加入会出错,错误如下。

04-09 22:03:55.748: E/AndroidRuntime(4089): FATAL EXCEPTION: main
04-09 22:03:55.748: E/AndroidRuntime(4089): java.lang.RuntimeException: Fail to connect to camera service
04-09 22:03:55.748: E/AndroidRuntime(4089): at android.hardware.Camera.native_setup(Native Method)
04-09 22:03:55.748: E/AndroidRuntime(4089): at android.hardware.Camera.(Camera.java:185)
04-09 22:03:55.748: E/AndroidRuntime(4089): at android.hardware.Camera.open(Camera.java:165)
04-09 22:03:55.748: E/AndroidRuntime(4089): at com.jouhu.opencvffmpeg.Preview.surfaceCreated(FacePreview.java:225)
04-09 22:03:55.748: E/AndroidRuntime(4089): at android.view.SurfaceView.updateWindow(SurfaceView.java:536)
04-09 22:03:55.748: E/AndroidRuntime(4089): at android.view.SurfaceView.dispatchDraw(SurfaceView.java:339)
04-09 22:03:55.748: E/AndroidRuntime(4089): at android.view.ViewGroup.drawChild(ViewGroup.java:1638)
04-09 22:03:55.748: E/AndroidRuntime(4089): at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1367)
04-09 22:03:55.748: E/AndroidRuntime(4089): at android.view.ViewGroup.drawChild(ViewGroup.java:1638)
04-09 22:03:55.748: E/AndroidRuntime(4089): at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1367)
04-09 22:03:55.748: E/AndroidRuntime(4089): at android.view.View.draw(View.java:6832)
04-09 22:03:55.748: E/AndroidRuntime(4089): at android.widget.FrameLayout.draw(FrameLayout.java:352)
04-09 22:03:55.748: E/AndroidRuntime(4089): at android.view.ViewGroup.drawChild(ViewGroup.java:1640)
04-09 22:03:55.748: E/AndroidRuntime(4089): at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1367)
04-09 22:03:55.748: E/AndroidRuntime(4089): at android.view.View.draw(View.java:6832)
04-09 22:03:55.748: E/AndroidRuntime(4089): at android.widget.FrameLayout.draw(FrameLayout.java:352)
04-09 22:03:55.748: E/AndroidRuntime(4089): at com.android.internal.policy.impl.PhoneWindow$DecorView.draw(PhoneWindow.java:1895)
04-09 22:03:55.748: E/AndroidRuntime(4089): at android.view.ViewRoot.draw(ViewRoot.java:1407)
04-09 22:03:55.748: E/AndroidRuntime(4089): at android.view.ViewRoot.performTraversals(ViewRoot.java:1163)
04-09 22:03:55.748: E/AndroidRuntime(4089): at android.view.ViewRoot.handleMessage(ViewRoot.java:1727)
04-09 22:03:55.748: E/AndroidRuntime(4089): at android.os.Handler.dispatchMessage(Handler.java:99)
04-09 22:03:55.748: E/AndroidRuntime(4089): at android.os.Looper.loop(Looper.java:123)
04-09 22:03:55.748: E/AndroidRuntime(4089): at android.app.ActivityThread.main(ActivityThread.java:4627)
04-09 22:03:55.748: E/AndroidRuntime(4089): at java.lang.reflect.Method.invokeNative(Native Method)
04-09 22:03:55.748: E/AndroidRuntime(4089): at java.lang.reflect.Method.invoke(Method.java:521)
04-09 22:03:55.748: E/AndroidRuntime(4089): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:858)
04-09 22:03:55.748: E/AndroidRuntime(4089): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
04-09 22:03:55.748: E/AndroidRuntime(4089): at dalvik.system.NativeStart.main(Native Method)




6 代码下载

由于里面包含了很多so文件,所有代码非常大。我将所有的.so去掉附上代码。
OpenCVFFmpegTest.tar

7 参考文章
7.1 http://code.google.com/p/javacv/
7.2 http://code.google.com/p/javacv/issues/detail?id=183&can=1&start=100

移植开源EasyPR的车牌识别源码到Android工程

基于开源EasyPR的车牌识别Android工程源码
  • daiyinger
  • daiyinger
  • 2016年01月24日 18:10
  • 8423

opencv之android开源版(牛B的技术)

android-opencv是一个将OpenCV移到Android手机平台的开源项目,该项目使用OpenCV最新的一个分枝并利用一个改良过的Android NDK进行构建。 http://c...
  • jingwen3699
  • jingwen3699
  • 2012年07月24日 17:24
  • 1745

【Android】JavaCV and OpenCV

package com.duanjiwei.takephoto; import android.app.Activity; import android.content.Context; impor...
  • Taily_Duan
  • Taily_Duan
  • 2016年09月18日 17:26
  • 1806

Android studio2.3.3配置JavaCV1.3.3

Android studio2.3.3配置JavaCV1.3.3
  • redfoxtao
  • redfoxtao
  • 2017年09月14日 22:19
  • 388

【Java CV与Android】在Android工程里配置JavaCV

版权声明:本文转载自这位大神 http://blog.csdn.net/zgljl2012/article/details/48193859 目录(?)[-] 具体配置过程 实例 在Andro...
  • abcd112358
  • abcd112358
  • 2015年12月20日 17:00
  • 2030

OpenCV Java教程文档及深入学习图书

OpenCV是一个基于BSD许可(开源)发行的跨平台计算机视觉库,可以运行在Linux、Windows、Android和Mac OS操作系统上。它轻量级而且高效——由一系列 C 函数和少量 C++ 类...
  • boonya
  • boonya
  • 2017年11月27日 17:01
  • 211

opencv3 环境安装及实验surf特征的描述符匹配文章整理

OpenCV3.1 SIFT使用 OpenCV3对OpenCV的模块进行了调整,将开发中与nofree模块放在 了OpenCV_contrib中(包含SIFT),gitHub上的官方项目分成了两个...
  • luopeiyuan1990
  • luopeiyuan1990
  • 2017年04月25日 21:52
  • 887

SurfaceView+Camera+OpenCv自定义相机保存图片

在Activity中实现CameraBridgeViewBase.CvCameraViewListener2接口并重写其方法,在 Mat onCameraFrame(CameraBridgeView...
  • yd_yandong
  • yd_yandong
  • 2016年10月12日 11:07
  • 965

【android 使用两个surfaceview 在摄像机画面上绘图】

使用双surface,将第一个设置为透明背景,在摄像机上绘制图像,纠结搞了一天。 其中参考了http://blog.csdn.net/yanzi1225627/article/details/793...
  • Jesse__Zhong
  • Jesse__Zhong
  • 2014年05月03日 21:03
  • 9645

Android Studio 通过NDK调用OpenCV

所用as版本为2.0 ndk版本为r10d 安卓版本为5.0 系统为win10首先新建一个工程然后将sdk目录下的native文件夹复制过来 然后在app/src/main文件夹下新建一个文件夹...
  • qq_22033759
  • qq_22033759
  • 2016年05月25日 20:03
  • 3042
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Android使用OpenCV和FFMpeg的简单方法-开源项目javacv的使用
举报原因:
原因补充:

(最多只允许输入30个字)