Opencv On Android Studio: 使用获取手机摄像头数据并显示

本文详细介绍了如何在Android Studio中集成OpenCV库,包括使用Java库进行摄像头数据处理和显示,以及通过CMake和JNI调用OpenCV函数的方法。涵盖了项目设置、权限配置、代码实现等关键步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Opencv On Android Studio: 使用获取手机摄像头数据并显示

    1. 新建空项目
    2. 将opencv的Java库作为Module导入

具体步骤为: File->new->Import,选择opencv-4.1.1-android-sdk\OpenCV-android-sdk\sdk(opencv-4.1.1-android-sdk从Opencv官网下载)

    1. 修改opencv的build.gradle文件版本号

具体做法是,将文件列表上方的显示模式由Android切换至 Project,并展开文件列表。分别打开app\build.gradle文件和opencv411\build.gradle文件,将opencv411\build.gradle的几个版本号改成app\build.gradle文件里相同即可,然后在在文本域上点击 Try Again或工具栏图标

    1. 添加opencv411作为项目依赖module

打开File->Project Structure,在Modules里选择app,右侧进入Dependencies,点击加号,选择Module dependency。

    1. AndroidMainfest.xml文件中添加Opencv权限

AndroidMainfest.xml的路径为myopencvTest\app\src\main\AndroidMainfest.xml

 

<uses-permission android:name="android.permission.CAMERA"/>
<
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"/>

 

    1. 修改activity_main.xml的内容

activity_main.xml 的路径为myopencvTest\app\src\main\res\layout\activity_main.xml

 

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"

    xmlns:tools="http://schemas.android.com/tools"

    xmlns:opencv="http://schemas.android.com/apk/res-auto"

    android:layout_width="match_parent"

    android:layout_height="match_parent" >



    <org.opencv.android.JavaCameraView

        android:layout_width="fill_parent"

        android:layout_height="fill_parent"

        android:visibility="gone"

        android:id="@+id/tutorial1_activity_java_surface_view"

        opencv:show_fps="true"

        opencv:camera_id="any" />



</FrameLayout>

 

    1. 修改MainActivity.java的内容

内容如下所示:

public class MainActivity extends CameraActivity implements CameraBridgeViewBase.CvCameraViewListener2 {

    private static final String TAG = "OCVSample::Activity";



    private CameraBridgeViewBase mOpenCvCameraView;

    private boolean              mIsJavaCamera = true;

    private MenuItem             mItemSwitchCamera = null;



    private BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this) {

        @Override

        public void onManagerConnected(int status) {

            switch (status) {

                case LoaderCallbackInterface.SUCCESS:

                {

                    Log.i(TAG, "OpenCV loaded successfully");

                    mOpenCvCameraView.enableView();

                } break;

                default:

                {

                    super.onManagerConnected(status);

                } break;

            }

        }

    };



    public MainActivity() {

        Log.i(TAG, "Instantiated new " + this.getClass());

    }



    /** Called when the activity is first created. */

    @Override

    public void onCreate(Bundle savedInstanceState) {

        Log.i(TAG, "called onCreate");

        super.onCreate(savedInstanceState);

        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);



        setContentView(R.layout.activity_main);



        mOpenCvCameraView = (CameraBridgeViewBase) findViewById(R.id.tutorial1_activity_java_surface_view);



        mOpenCvCameraView.setVisibility(SurfaceView.VISIBLE);



        mOpenCvCameraView.setCvCameraViewListener(this);

    }



    @Override

    public void onPause()

    {

        super.onPause();

        if (mOpenCvCameraView != null)

            mOpenCvCameraView.disableView();

    }



    @Override

    public void onResume()

    {

        super.onResume();

        if (!OpenCVLoader.initDebug()) {

            Log.d(TAG, "Internal OpenCV library not found. Using OpenCV Manager for initialization");

            OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_3_0_0, this, mLoaderCallback);

        } else {

            Log.d(TAG, "OpenCV library found inside package. Using it!");

            mLoaderCallback.onManagerConnected(LoaderCallbackInterface.SUCCESS);

        }

    }



    @Override

    protected List<? extends CameraBridgeViewBase> getCameraViewList() {

        return Collections.singletonList(mOpenCvCameraView);

    }



    public void onDestroy() {

        super.onDestroy();

        if (mOpenCvCameraView != null)

            mOpenCvCameraView.disableView();

    }



    public void onCameraViewStarted(int width, int height) {

    }



    public void onCameraViewStopped() {

    }



    public Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame inputFrame) {

        return inputFrame.rgba();

    }

}

 

    1. 参考网址

https://www.jianshu.com/p/6e16c0429044

 

Android Studio 使用CMake并用jni调用opencv函数

    1. 将CMakelists.txt复制到工程app目录之下,如下图所示

    1. 在CMakelists.txt中添加使用opencv的so库及cpp文件,并包含头文件

修改后的CMakelists.txt如下所示:

cmake_minimum_required(VERSION 3.4.1)



# OpenCV stuff

set(OpenCV_DIR D:/ProgramData/opencv/OpenCV-android-sdk/sdk/native/jni)

find_package(OpenCV REQUIRED)



add_library( # Sets the name of the library.

             native-lib



             # Sets the library as a shared library.

             SHARED



             # Provides a relative path to your source file(s).

             # Associated headers in the same location as their source

             # file are automatically included.

             src/main/cpp/native-lib.cpp )



find_library( # Sets the name of the path variable.

              log-lib



              # Specifies the name of the NDK library that

              # you want CMake to locate.

              log )



include_directories(D:/ProgramData/opencv/OpenCV-android-sdk/sdk/native/jni/include)

add_library( lib_opencv SHARED IMPORTED )

set_target_properties(

        lib_opencv

        PROPERTIES IMPORTED_LOCATION

        D:/ProgramData/opencv/OpenCV-android-sdk/sdk/native/libs/armeabi-v7a/libopencv_java4.so

)





target_link_libraries( # Specifies the target library.

                       native-lib



                       # OpenCV lib



                        ${lib_opencv}



                       # Links the target library to the log library

                       # included in the NDK.

                       ${log-lib} )
    1. 修改gradle配置,将gradle与CMakelists.txt的原生库关联,并指定ABI

其中,添加的模块为:

ndk{
            abiFilters
'x86', 'x86_64', 'armeabi-v7a', 'arm64-v8a'
       
}
        externalNativeBuild {
            cmake {
                cppFlags
"-frtti -fexceptions"
               
abiFilters 'x86', 'x86_64', 'armeabi-v7a', 'arm64-v8a'
           
}
        }

配置gradle与CMakelist文件关联,内容如下所示:

externalNativeBuild {
        cmake {
            path
"CMakeLists.txt"
       
}
    }

 

修改后的app/build.gradle内容如下所示:

apply plugin: 'com.android.application'



android {

    compileSdkVersion 29

    buildToolsVersion "29.0.1"

    defaultConfig {

        applicationId "com.example.testapplication"

        minSdkVersion 26

        targetSdkVersion 29

        versionCode 1

        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"



        ndk{

            abiFilters 'x86', 'x86_64', 'armeabi-v7a', 'arm64-v8a'

        }

        externalNativeBuild {

            cmake {

                cppFlags "-frtti -fexceptions"

                abiFilters 'x86', 'x86_64', 'armeabi-v7a', 'arm64-v8a'

            }

        }

    }



    externalNativeBuild {

        cmake {

            path "CMakeLists.txt"

        }

    }



    buildTypes {

        release {

            minifyEnabled false

            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'

        }

    }



}

dependencies {

    implementation fileTree(dir: 'libs', include: ['*.jar'])

    implementation 'androidx.appcompat:appcompat:1.0.2'

    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'

    implementation 'com.google.android.material:material:1.0.0'

    testImplementation 'junit:junit:4.12'

    androidTestImplementation 'androidx.test:runner:1.2.0'

    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'

    compile project(path: ':opencv411sdk')

}
    1. MainActivity.java中添加自定义的C++库
System.loadLibrary("native-lib");
    1. 调用jni函数

定义:

public native void salt(long matAddrGray, int nbrElem);

调用:

public Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame inputFrame) {

    Mat matGray = inputFrame.gray();

    salt(matGray.getNativeObjAddr(), 100);

    Log.i(TAG, "onCameraFrame");

    return matGray;

}

 

    1. 参考网址

https://www.jianshu.com/p/23af9151837e

 

 

<think>好的,用户之前问了如何在Android Studio中实现拍照功能,我介绍了使用系统相机的方法。现在用户进一步询问使用Camera2 API实现预览、对焦和获取处理YUV数据且是针对Android 13的。我需要详细解答,同时确保覆盖最新的Android版本的要求。 首先,权限部分可能需要更新。Android 13对权限有更严格的要求,比如摄像头权限可能需要在运行时请求,而存储权限可能有所变化。需要确认是否需要使用MediaStore代替直接文件访问。 然后,Camera2 API的基本流程需要覆盖:打开摄像头、创建预览会话、配置CaptureRequest处理对焦。用户提到对焦,可能需要解释自动对焦模式,比如CONTINUOUS_PICTURE。 接下来是YUV数据的处理。ImageReader的使用是关键,设置YUV_420_888格式,在Image回调中处理数据。这里需要注意如何正确地从Image对象中提取YUV数据,尤其是不同Plane的处理,以及可能的旋转问题。 Android 13的变化可能需要特别注意,比如作用域存储、后台访问摄像头的限制,或者权限的变更。例如,Android 13引入了NEARBY_WIFI_DEVICES权限,但和摄像头无关,但可能需要检查是否有其他权限调整。 另外,用户可能需要了解如何将YUV数据转换为RGB或进行其他图像处理,但用户的问题可能更关注获取数据而不是处理,所以是否需要给出示例代码或推荐库?比如使用RenderScript或OpenCV进行转换。 测试方面,需要提醒用户使用真机,因为模拟器可能不支持Camera2 API的所有功能,特别是对焦和YUV数据流。 可能用户的实际需求是实时图像处理,比如人脸识别或AR应用,所以处理YUV数据的高效性很重要。可以建议使用SurfaceTexture配合TextureView或SurfaceView来显示预览,同时用ImageReader获取YUV帧。 还需要考虑Camera2 API的异步特性,正确管理CameraDevice和CaptureSession的状态,避免资源泄露。例如在onPause时关闭摄像头会话。 最后,检查是否有遗漏的步骤,比如CameraCharacteristics的查询,确定摄像头支持的能力,比如支持的硬件级别、自动对焦模式等。确保代码示例中的错误处理,比如摄像头无法打开时的回调处理。 总结回答的结构:权限、Camera2初始化、预览设置、对焦配置、YUV数据处理、Android 13适配注意事项、示例代码和注意事项。确保代码示例使用Kotlin还是Java?用户之前的回答是Java,可能需要保持一致,但Android开发现在更多转向Kotlin,不过还是先用Java示例,除非用户特别说明。 需要验证代码是否适配Android 13,比如FileProvider的配置是否仍然适用,或者是否需要使用MediaStore来保存图片。但在这个问题中,用户可能不需要保存图片,而是处理实时数据,所以重点在权限和摄像头访问流程。</think>在 Android 13 上使用 Camera2 API 实现相机预览、对焦及 YUV 数据处理,需要注意新版系统的权限变化和 API 兼容性。以下是关键实现步骤: --- ### 一、Android 13 适配要点 1. **权限声明**: ```xml <!-- AndroidManifest.xml --> <uses-permission android:name="android.permission.CAMERA" /> <!-- 不再需要 WRITE_EXTERNAL_STORAGE --> ``` Android 13 已废弃 `READ/WRITE_EXTERNAL_STORAGE`,建议通过 `MediaStore` API 管理文件 2. **动态权限请求**: ```java private final String[] REQUIRED_PERMISSIONS = new String[]{ Manifest.permission.CAMERA }; private void requestPermissions() { if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, REQUIRED_PERMISSIONS, REQUEST_CODE); } else { openCamera(); } } ``` --- ### 二、Camera2 API 核心实现 #### 1. 初始化相机 ```java private CameraDevice mCameraDevice; private String mCameraId; private CameraManager mCameraManager; private void openCamera() { mCameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE); try { mCameraId = getBackCameraId(); // 获取后置摄像头ID CameraCharacteristics characteristics = mCameraManager.getCameraCharacteristics(mCameraId); // 检查自动对焦支持 int[] afModes = characteristics.get(CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES); boolean hasAutoFocus = Arrays.stream(afModes).anyMatch(mode -> mode == CameraCharacteristics.CONTROL_AF_MODE_CONTINUOUS_PICTURE); if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) { mCameraManager.openCamera(mCameraId, mStateCallback, null); } } catch (CameraAccessException e) { e.printStackTrace(); } } private String getBackCameraId() throws CameraAccessException { for (String cameraId : mCameraManager.getCameraIdList()) { CameraCharacteristics characteristics = mCameraManager.getCameraCharacteristics(cameraId); Integer facing = characteristics.get(CameraCharacteristics.LENS_FACING); if (facing != null && facing == CameraCharacteristics.LENS_FACING_BACK) { return cameraId; } } return null; } ``` #### 2. 创建预览会话 ```java private CaptureRequest.Builder mPreviewRequestBuilder; private CameraCaptureSession mCaptureSession; private void createPreviewSession(SurfaceTexture texture) { texture.setDefaultBufferSize(640, 480); // 设置预览分辨率 Surface previewSurface = new Surface(texture); try { mPreviewRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); mPreviewRequestBuilder.addTarget(previewSurface); // 添加YUV数据输出 ImageReader imageReader = ImageReader.newInstance(640, 480, ImageFormat.YUV_420_888, 2); // YUV格式 imageReader.setOnImageAvailableListener(mImageListener, null); mPreviewRequestBuilder.addTarget(imageReader.getSurface()); mCameraDevice.createCaptureSession( Arrays.asList(previewSurface, imageReader.getSurface()), new CameraCaptureSession.StateCallback() { @Override public void onConfigured(@NonNull CameraCaptureSession session) { mCaptureSession = session; updatePreview(); } // ... 错误处理 }, null); } catch (CameraAccessException e) { e.printStackTrace(); } } ``` #### 3. 自动对焦配置 ```java private void updatePreview() { try { // 设置连续自动对焦模式 mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE); mCaptureSession.setRepeatingRequest( mPreviewRequestBuilder.build(), null, null); } catch (CameraAccessException e) { e.printStackTrace(); } } ``` --- ### 三、YUV数据处理(Android 13 适配版) ```java private ImageReader.OnImageAvailableListener mImageListener = reader -> { Image image = null; try { image = reader.acquireLatestImage(); if (image != null) { Image.Plane[] planes = image.getPlanes(); ByteBuffer yBuffer = planes[0].getBuffer(); // Y分量 ByteBuffer uBuffer = planes[1].getBuffer(); // U分量 ByteBuffer vBuffer = planes[2].getBuffer(); // V分量 // 获取YUV数据(示例处理逻辑) int ySize = yBuffer.remaining(); byte[] yData = new byte[ySize]; yBuffer.get(yData); // TODO: 添加YUV处理逻辑(如转RGB/灰度处理等) } } finally { if (image != null) { image.close(); } } }; ``` --- ### 四、Android 13 特别注意事项 1. **后台限制**:应用进入后台时,系统会在 3 秒后关闭摄像头访问 2. **动态颜色空间**:支持 `Display#getHdrCapabilities` 检测 HDR 显示能力 3. **照片选择器**:建议使用系统照片选择器代替直接文件访问 4. **媒体权限**:使用 `READ_MEDIA_IMAGES` 代替旧版存储权限 --- ### 五、完整调用示例 ```java // 在TextureView.SurfaceTextureListener中启动 @Override public void onSurfaceTextureAvailable(SurfaceTexture texture, int width, int height) { openCamera(); createPreviewSession(texture); } // 释放资源 @Override protected void onPause() { if (mCaptureSession != null) { mCaptureSession.close(); mCaptureSession = null; } if (mCameraDevice != null) { mCameraDevice.close(); mCameraDevice = null; } super.onPause(); } ``` --- ### 六、优化建议 1. **YUV处理性能**:使用 `RenderScript` 或 `OpenCV` 进行高效图像处理 2. **帧率控制**:通过 `CaptureRequest.SENSOR_FRAME_DURATION` 设置帧间隔 3. **动态分辨率**:根据设备能力选择最佳分辨率 4. **错误处理**:实现 `CameraDevice.StateCallback` 处理设备异常 测试时请使用支持 Camera2 API 的 Android 13 真机设备,模拟器可能无法完整支持硬件相关功能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值