OpenCV-如何在Android中设置全屏摄像头视图? [英] OpenCV - How to set a Full Screen Camera view in Android?

查看:83
本文介绍了OpenCV-如何在Android中设置全屏摄像头视图?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

背景

作为软件新手,我目前的目标是将CameraPreview格式化为全屏显示,这与Snapchat上的摄像头预览相同.现在,我可以按照.

我要消除预览上方和下方的黑色边框,并允许相机占据整个屏幕.

MainActivity.java

  package com.example.cv;导入androidx.annotation.NonNull;导入androidx.appcompat.app.AppCompatActivity;导入androidx.core.app.ActivityCompat;导入androidx.core.content.ContextCompat;导入android.Manifest;导入android.content.pm.PackageManager;导入android.opengl.Matrix;导入android.os.Bundle;导入android.util.Log;导入android.view.SurfaceView;导入android.view.WindowManager;导入android.widget.Toast;导入org.opencv.android.BaseLoaderCallback;导入org.opencv.android.CameraBridgeViewBase;导入org.opencv.android.JavaCameraView;导入org.opencv.android.OpenCVLoader;导入org.opencv.core.Core;导入org.opencv.core.CvType;导入org.opencv.core.Mat;导入org.opencv.imgproc.Imgproc;公共类MainActivity扩展AppCompatActivity实现CameraBridgeViewBase.CvCameraViewListener2{private static String TAG ="MainActivity";JavaCameraView javaCameraView;垫mRGBA,mRGBAT,dst;私有静态最终整数MY_CAMERA_REQUEST_CODE = 100;BaseLoaderCallback baseLoaderCallback = new BaseLoaderCallback(MainActivity.this){@Override公共无效的onManagerConnected(int状态){如果(状态== BaseLoaderCallback.SUCCESS){javaCameraView.enableView();} 别的 {super.onManagerConnected(状态);}}};静态的{如果(OpenCVLoader.initDebug()){Log.d(TAG,"OpenCV已成功配置或连接.");}别的{Log.d(TAG,"OpenCV不工作或未加载.");}}@Override受保护的void onCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);javaCameraView =(JavaCameraView)findViewById(R.id.my_camera_view);如果(ContextCompat.checkSelfPermission(this,Manifest.permission.CAMERA)== PackageManager.PERMISSION_GRANTED){Log.d(TAG,已授予权限");javaCameraView.setCameraPermissionGranted();javaCameraView.setCameraIndex(CameraBridgeViewBase.CAMERA_ID_BACK);javaCameraView.setVisibility(CameraBridgeViewBase.VISIBLE);javaCameraView.setCvCameraViewListener(this);} 别的 {Log.d(TAG,权限提示");ActivityCompat.requestPermissions(此为新的String [] {Manifest.permission.CAMERA},MY_CAMERA_REQUEST_CODE);}}@Overridepublic void onCameraViewStarted(int width,int height){mRGBAT =新的Mat();dst = new Mat();}@OverrideonCameraViewStopped()上的公共无效{mRGBA.release();}@Override公共Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame inputFrame){mRGBA = inputFrame.rgba();Core.transpose(mRGBA,mRGBAT);Core.flip(mRGBAT,mRGBAT,1);Imgproc.resize(mRGBAT,dst,mRGBA.size());mRGBA.release();mRGBAT.release();返回dst;}@Override公共无效onPointerCaptureChanged(boolean hasCapture){}@Override受保护的void onDestroy(){super.onDestroy();如果(javaCameraView!= null){javaCameraView.disableView();}}@Override受保护的void onPause(){super.onPause();如果(javaCameraView!= null){javaCameraView.disableView();}}@Override受保护的void onResume(){super.onResume();如果(OpenCVLoader.initDebug()){Log.d(TAG,"OpenCV已成功配置或连接.");baseLoaderCallback.onManagerConnected(BaseLoaderCallback.SUCCESS);}别的{Log.d(TAG,"OpenCV不工作或未加载.");OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION,this,baseLoaderCallback);}}@Overridepublic void onRequestPermissionsResult(int requestCode,@NonNull String []权限,@NonNull int [] grantResults){super.onRequestPermissionsResult(requestCode,权限,grantResults);如果(requestCode == MY_CAMERA_REQUEST_CODE){//可以开启相机Toast.makeText(this,授予摄像机权限",Toast.LENGTH_LONG).show();javaCameraView.setCameraPermissionGranted();javaCameraView.setCameraIndex(CameraBridgeViewBase.CAMERA_ID_FRONT);javaCameraView.setVisibility(CameraBridgeViewBase.VISIBLE);javaCameraView.setCvCameraViewListener(this);} 别的 {//相机将保持关闭状态Toast.makeText(this,相机权限被拒绝",Toast.LENGTH_LONG).show();}}} 

activity_main.xml

 <?xml version ="1.0"encoding ="utf-8"?< RelativeLayoutxmlns:android ="http://schemas.android.com/apk/res/android"xmlns:app =" http://schemas.android.com/apk/res-autoxmlns:tools ="http://schemas.android.com/tools"android:layout_width =" match_parent"android:layout_height =" match_parent"工具:context =.MainActivity".< org.opencv.android.JavaCameraViewandroid:id =" @ + id/my_camera_view"android:layout_width =" fill_parent"android:layout_height =" fill_parent"/></RelativeLayout> 

AndroidManifest.xml

 <?xml version ="1.0"encoding ="utf-8"?<清单xmlns:android =" http://schemas.android.com/apk/res/android"package ="com.example.cv"< supports-screens android:resizeable ="true"android:smallScreens =" true"android:normalScreens =" true"android:largeScreens =" true"android:anyDensity ="true"/>< uses-permission android:name ="android.permission.CAMERA"/>< uses-feature android:name =" android.hardware.camera"/>< uses-feature android:name =" android.hardware.camera.autofocus"/>< uses-feature android:name =" android.hardware.camera.front"/>< uses-feature android:name =" android.hardware.camera.front.autofocus"/><应用android:allowBackup =" true"android:icon =&"; @ mipmap/ic_launcher;android:label =" @ string/app_name"android:roundIcon =" @ mipmap/ic_launcher_round"android:supportsRtl =" true"android:theme =" @ style/Theme.AppCompat.Light.NoActionBar">< activity android:name =" .MainActivity"android:screenOrientation ="portrait"android:configChanges ="keyboardHidden | orientation"><意图过滤器>< action android:name =" android.intent.action.MAIN"/>< category android:name =" android.intent.category.LAUNCHER"/></intent-filter></activity></应用程序></manifest> 

更新:我遇到了一些旨在改变方向和/或消除操作栏的解决方案.除了扩展CameraPreview的分辨率外,应用 setMaxFrameSize()无效.我看到的另一个答案是 getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); ,由于不再使用 FLAG_KEEP_SCREEN_ON ,它不再有效.如果有人可以就我如何解决这个问题提供一点点解决方案,我将永远感激不已.

更新2 :我试图修改我的 activity_main.xml 文件中的 layout_height ,只是让它将预览进一步推向了屏幕,但仍保留1:1框格式.另外,我还考虑过在MainActivity中实现 javaCameraView.getLayoutParams().height = 只是为了使它扭曲/拉伸相机预览而没有达到我的期望.

解决方案

Ciao,

简短答案

在代码说明之后,我最后将为 MainActivity 类提供完整的解决方案-包括后置和前置摄像头-


详细信息

我在此网站上加入了一些答案,并修改了 onCameraFrame().现在,我可以以纵向模式打开该应用程序,即使用本机Android相机或Snapchat视图

此解决方案非常轻巧,我没有像在此网站上的其他答案一样更改任何OpenCV文件.这一个].根据您要使用的 activeCamera 来确定[即[后退或前退]], onCameraFrame()内部需要进行一些修改,我将在下面列出

公共基础

因此,我首先按照此答案中的4个步骤进行操作,完全按照此处的说明进行操作,确实使我受益正确的轨道.值得一提的是,通过这些更改,您将立即获得漂亮的横向视图,但是一旦将手机置于纵向位置,上下黑带就会恢复.将步骤3的行更改为:

  android:screenOrientation ="portrait" 

没有为我解决.另外,如果要全屏显示,则需要删除标题栏,为此,我加入了此答案也.这意味着您还需要在上一步2

中的 AndroidManifest.xml 中修改此行

  android:theme =" @ style/Theme.AppCompat.Light.NoActionBar.FullScreen"" 

由于您在两个位置初始化了相机,并且需要对其进行更改[当前片段适用于前置相机,因此您需要后置相机],因此您可以清理代码并开始定义所需的相机,以便只能在一处修改输入源:

 公共类MainActivity扩展了AppCompatActivity实现CameraBridgeViewBase.CvCameraViewListener2{...//后置摄像头int activeCamera = CameraBridgeViewBase.CAMERA_ID_BACK;//前置摄像头//int activeCamera = CameraBridgeViewBase.CAMERA_ID_FRONT; 

然后将其传递给新的 initializeCamera()方法

  private void initializeCamera(JavaCameraView javaCameraView,int activeCamera){javaCameraView.setCameraPermissionGranted();javaCameraView.setCameraIndex(activeCamera);javaCameraView.setVisibility(CameraBridgeViewBase.VISIBLE);javaCameraView.setCvCameraViewListener(this);} 

您必须在Android检测到用户已授予 CAMERA 权限后立即致电:

:

 如果(ContextCompat.checkSelfPermission(this,Manifest.permission.CAMERA)== PackageManager.PERMISSION_GRANTED){Log.d(TAG,已授予权限");initializeCamera(javaCameraView,activeCamera); 

和:

 如果(requestCode == MY_CAMERA_REQUEST_CODE){如果(grantResults [0] == PackageManager.PERMISSION_GRANTED){Toast.makeText(this,授予摄像机权限",Toast.LENGTH_LONG).show();initializeCamera(javaCameraView,activeCamera); 

现在是区分前置和后置摄像头的时候了

后置摄像头

在这种情况下,您根本不需要操纵框架,代码如下:

  @Overridepublic void onCameraViewStarted(int width,int height){}@Override公共Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame inputFrame){mRGBA = inputFrame.rgba();返回mRGBA;} 

前置摄像头

在这种情况下,您需要稍微操作一下翻转框架,否则您的人像模式将倒置显示

  @Overridepublic void onCameraViewStarted(int width,int height){mRGBAT =新的Mat();}@Override公共Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame inputFrame){mRGBA = inputFrame.rgba();//翻转以正确显示人像模式Core.flip(mRGBA,mRGBAT,1);//发布不再需要的内容mRGBA.release();返回mRGBAT;} 

最后,请确保确实需要添加到代码中的框架操作.他们的处理时间降低了性能,甚至可能使您面临不必要的麻烦.我没有正确检查,但我很确定在您的 onCameraFrame()中转置矩阵是导致失真的根本原因


用于后置摄像头的MainActivity

  package com.change.package.name;导入android.Manifest;导入android.content.pm.PackageManager;导入android.os.Bundle;导入android.util.Log;导入android.view.WindowManager;导入android.widget.Toast;导入androidx.annotation.NonNull;导入androidx.appcompat.app.AppCompatActivity;导入androidx.core.app.ActivityCompat;导入androidx.core.content.ContextCompat;导入org.opencv.android.BaseLoaderCallback;导入org.opencv.android.CameraBridgeViewBase;导入org.opencv.android.JavaCameraView;导入org.opencv.android.OpenCVLoader;导入org.opencv.core.Core;导入org.opencv.core.Mat;公共类MainActivity扩展了AppCompatActivity实现CameraBridgeViewBase.CvCameraViewListener2{private static String TAG ="MainActivity";JavaCameraView javaCameraView;垫mRGBA;私有静态最终整数MY_CAMERA_REQUEST_CODE = 100;int activeCamera = CameraBridgeViewBase.CAMERA_ID_BACK;BaseLoaderCallback baseLoaderCallback = new BaseLoaderCallback(MainActivity.this){@Override公共无效的onManagerConnected(int状态){如果(状态== BaseLoaderCallback.SUCCESS){javaCameraView.enableView();} 别的 {super.onManagerConnected(状态);}}};静态的{如果(OpenCVLoader.initDebug()){Log.d(TAG,"OpenCV已成功配置或连接.");}别的{Log.d(TAG,"OpenCV不工作或未加载.");}}@Override受保护的void onCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);javaCameraView =(JavaCameraView)findViewById(R.id.my_camera_view);getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);如果(ContextCompat.checkSelfPermission(this,Manifest.permission.CAMERA)== PackageManager.PERMISSION_GRANTED){Log.d(TAG,已授予权限");initializeCamera(javaCameraView,activeCamera);} 别的 {Log.d(TAG,故障");ActivityCompat.requestPermissions(此为新的String [] {Manifest.permission.CAMERA},MY_CAMERA_REQUEST_CODE);}}@Overridepublic void onRequestPermissionsResult(int requestCode,@NonNull String []权限,@NonNull int [] grantResults){super.onRequestPermissionsResult(requestCode,权限,grantResults);如果(requestCode == MY_CAMERA_REQUEST_CODE){如果(grantResults [0] == PackageManager.PERMISSION_GRANTED){Toast.makeText(this,授予摄像机权限",Toast.LENGTH_LONG).show();initializeCamera(javaCameraView,activeCamera);} 别的 {Toast.makeText(this,摄像机权限被拒绝",Toast.LENGTH_LONG).show();}}}私有无效的initializeCamera(JavaCameraView javaCameraView,int activeCamera){javaCameraView.setCameraPermissionGranted();javaCameraView.setCameraIndex(activeCamera);javaCameraView.setVisibility(CameraBridgeViewBase.VISIBLE);javaCameraView.setCvCameraViewListener(this);}@Overridepublic void onCameraViewStarted(int width,int height){}@OverrideonCameraViewStopped()上的公共无效{mRGBA.release();}@Override公共Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame inputFrame){//后置摄像头的代码mRGBA = inputFrame.rgba();返回mRGBA;}@Override公共无效onPointerCaptureChanged(boolean hasCapture){}@Override受保护的void onDestroy(){super.onDestroy();如果(javaCameraView!= null){javaCameraView.disableView();}}@Override受保护的void onPause(){super.onPause();如果(javaCameraView!= null){javaCameraView.disableView();}}@Override受保护的void onResume(){super.onResume();如果(OpenCVLoader.initDebug()){Log.d(TAG,"OpenCV已成功配置或连接.");baseLoaderCallback.onManagerConnected(BaseLoaderCallback.SUCCESS);}别的{Log.d(TAG,"OpenCV不工作或未加载.");OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION,this,baseLoaderCallback);}}} 

前置摄像头的MainActivity

  package com.change.package.name;导入android.Manifest;导入android.content.pm.PackageManager;导入android.os.Bundle;导入android.util.Log;导入android.view.WindowManager;导入android.widget.Toast;导入androidx.annotation.NonNull;导入androidx.appcompat.app.AppCompatActivity;导入androidx.core.app.ActivityCompat;导入androidx.core.content.ContextCompat;导入org.opencv.android.BaseLoaderCallback;导入org.opencv.android.CameraBridgeViewBase;导入org.opencv.android.JavaCameraView;导入org.opencv.android.OpenCVLoader;导入org.opencv.core.Core;导入org.opencv.core.Mat;公共类MainActivity扩展了AppCompatActivity实现CameraBridgeViewBase.CvCameraViewListener2{private static String TAG ="MainActivity";JavaCameraView javaCameraView;垫子mRGBA,mRGBAT;私有静态最终整数MY_CAMERA_REQUEST_CODE = 100;int activeCamera = CameraBridgeViewBase.CAMERA_ID_FRONT;BaseLoaderCallback baseLoaderCallback = new BaseLoaderCallback(MainActivity.this){@Override公共无效的onManagerConnected(int状态){如果(状态== BaseLoaderCallback.SUCCESS){javaCameraView.enableView();} 别的 {super.onManagerConnected(状态);}}};静态的{如果(OpenCVLoader.initDebug()){Log.d(TAG,"OpenCV已成功配置或连接.");}别的{Log.d(TAG,"OpenCV不工作或未加载.");}}@Override受保护的void onCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);javaCameraView =(JavaCameraView)findViewById(R.id.my_camera_view);getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);如果(ContextCompat.checkSelfPermission(this,Manifest.permission.CAMERA)== PackageManager.PERMISSION_GRANTED){Log.d(TAG,已授予权限");initializeCamera(javaCameraView,activeCamera);} 别的 {Log.d(TAG,故障");ActivityCompat.requestPermissions(此为新的String [] {Manifest.permission.CAMERA},MY_CAMERA_REQUEST_CODE);}}@Overridepublic void onRequestPermissionsResult(int requestCode,@NonNull String []权限,@NonNull int [] grantResults){super.onRequestPermissionsResult(requestCode,权限,grantResults);如果(requestCode == MY_CAMERA_REQUEST_CODE){如果(grantResults [0] == PackageManager.PERMISSION_GRANTED){Toast.makeText(this,授予摄像机权限",Toast.LENGTH_LONG).show();initializeCamera(javaCameraView,activeCamera);} 别的 {Toast.makeText(this,摄像机权限被拒绝",Toast.LENGTH_LONG).show();}}}私有无效的initializeCamera(JavaCameraView javaCameraView,int activeCamera){javaCameraView.setCameraPermissionGranted();javaCameraView.setCameraIndex(activeCamera);javaCameraView.setVisibility(CameraBridgeViewBase.VISIBLE);javaCameraView.setCvCameraViewListener(this);}@Overridepublic void onCameraViewStarted(int width,int height){mRGBAT =新的Mat();}@OverrideonCameraViewStopped()上的公共无效{mRGBA.release();}@Override公共Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame inputFrame){//前置摄像头的代码mRGBA = inputFrame.rgba();//翻转以正确显示人像模式Core.flip(mRGBA,mRGBAT,1);mRGBA.release();返回mRGBAT;}@Override公共无效onPointerCaptureChanged(boolean hasCapture){}@Override受保护的void onDestroy(){super.onDestroy();如果(javaCameraView!= null){javaCameraView.disableView();}}@Override受保护的void onPause(){super.onPause();如果(javaCameraView!= null){javaCameraView.disableView();}}@Override受保护的void onResume(){super.onResume();如果(OpenCVLoader.initDebug()){Log.d(TAG,"OpenCV已成功配置或连接.");baseLoaderCallback.onManagerConnected(BaseLoaderCallback.SUCCESS);}别的{Log.d(TAG,"OpenCV不工作或未加载.");OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION,this,baseLoaderCallback);}}} 

祝你有美好的一天,
安东尼诺

Background

As a novice in software, I am currently aiming to format my camerapreview to full screen, that would be identical to the camera preview on Snapchat. Right now, I am able to showcase my camera preview in a 1:1 box format that I was able to set by following this tutorial. Other potential solutions that I had encountered in other questions either stretched/distorted the previewed image, or didn't launch the application altogether. How would I be able to do this while still maintaining portrait mode? Code provided below

Additional device specifications include the fact that the device I aim to launch the application on is a OnePlus Six, and its aspect ratio is 19:9. This is what the camera on my application currently looks like this.

.

I want to eliminate the black borders above and below the preview and allow the camera to take up the entirety of the screen.

MainActivity.java

package com.example.cv;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

import android.Manifest;
import android.content.pm.PackageManager;
import android.opengl.Matrix;
import android.os.Bundle;
import android.util.Log;
import android.view.SurfaceView;
import android.view.WindowManager;
import android.widget.Toast;

import org.opencv.android.BaseLoaderCallback;
import org.opencv.android.CameraBridgeViewBase;
import org.opencv.android.JavaCameraView;
import org.opencv.android.OpenCVLoader;
import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.imgproc.Imgproc;

public class MainActivity extends AppCompatActivity implements CameraBridgeViewBase.CvCameraViewListener2
{
    private static String TAG = "MainActivity";
    JavaCameraView javaCameraView;
    Mat mRGBA, mRGBAT, dst;

    private static final int MY_CAMERA_REQUEST_CODE = 100;


    BaseLoaderCallback baseLoaderCallback = new BaseLoaderCallback(MainActivity.this) {
        @Override
        public void onManagerConnected(int status)
        {
            if (status == BaseLoaderCallback.SUCCESS) {
                javaCameraView.enableView();
            } else {
                super.onManagerConnected(status);
            }
        }
    };

    static
    {
        if (OpenCVLoader.initDebug())
        {
            Log.d(TAG, "OpenCV is Configured or Connected successfully.");
        }
        else
        {
            Log.d(TAG, "OpenCV not Working or Loaded.");
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        javaCameraView = (JavaCameraView) findViewById(R.id.my_camera_view);



        if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
                == PackageManager.PERMISSION_GRANTED)  {
            Log.d(TAG, "Permissions granted");
            javaCameraView.setCameraPermissionGranted();
            javaCameraView.setCameraIndex(CameraBridgeViewBase.CAMERA_ID_BACK);
            javaCameraView.setVisibility(CameraBridgeViewBase.VISIBLE);
            javaCameraView.setCvCameraViewListener(this);
        } else {
            Log.d(TAG, "Permission prompt");
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, MY_CAMERA_REQUEST_CODE);
        }



    }

    @Override
    public void onCameraViewStarted(int width, int height)
    {
        mRGBAT = new Mat();
        dst = new Mat();
    }

    @Override
    public void onCameraViewStopped()
    {
        mRGBA.release();
    }

    @Override
    public Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame inputFrame)
    {
        mRGBA = inputFrame.rgba();
        Core.transpose(mRGBA, mRGBAT);
        Core.flip(mRGBAT, mRGBAT, 1);
        Imgproc.resize(mRGBAT, dst, mRGBA.size());
        mRGBA.release();
        mRGBAT.release();
        return dst;
    }

    @Override
    public void onPointerCaptureChanged(boolean hasCapture) {

    }


    @Override
    protected void onDestroy() {
        super.onDestroy();

        if (javaCameraView != null)
        {
            javaCameraView.disableView();
        }
    }

    @Override
    protected void onPause() {
        super.onPause();

        if (javaCameraView != null)
        {
            javaCameraView.disableView();
        }
    }


    @Override
    protected void onResume() {
        super.onResume();

        if (OpenCVLoader.initDebug())
        {
            Log.d(TAG, "OpenCV is Configured or Connected successfully.");
            baseLoaderCallback.onManagerConnected(BaseLoaderCallback.SUCCESS);
        }
        else
        {
            Log.d(TAG, "OpenCV not Working or Loaded.");
            OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION, this, baseLoaderCallback);
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == MY_CAMERA_REQUEST_CODE) {
            // camera can be turned on
            Toast.makeText(this, "camera permission granted", Toast.LENGTH_LONG).show();
            javaCameraView.setCameraPermissionGranted();
            javaCameraView.setCameraIndex(CameraBridgeViewBase.CAMERA_ID_FRONT);
            javaCameraView.setVisibility(CameraBridgeViewBase.VISIBLE);
            javaCameraView.setCvCameraViewListener(this);
        } else {
            //camera will stay off
            Toast.makeText(this, "camera permission denied", Toast.LENGTH_LONG).show();
        }
    }
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">


    <org.opencv.android.JavaCameraView
        android:id="@+id/my_camera_view"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        />

</RelativeLayout>

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.cv">

    <supports-screens android:resizeable="true"
        android:smallScreens="true"
        android:normalScreens="true"
        android:largeScreens="true"
        android:anyDensity="true" />


    <uses-permission android:name="android.permission.CAMERA"/>
    <uses-feature android:name="android.hardware.camera"/>
    <uses-feature android:name="android.hardware.camera.autofocus"/>
    <uses-feature android:name="android.hardware.camera.front"/>
    <uses-feature android:name="android.hardware.camera.front.autofocus"/>

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.AppCompat.Light.NoActionBar">
        <activity android:name=".MainActivity"
            android:screenOrientation="portrait"
            android:configChanges="keyboardHidden|orientation">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

UPDATE: I have come across solutions that aim to change orientation and/or eliminate the action bar. Applying setMaxFrameSize() does not work aside from stretching the resolution of the CameraPreview. Another answer I have seen is getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); which is no longer valid as FLAG_KEEP_SCREEN_ON has been deprecated. If anyone can offer the slightest bit of solution as to how I can fix this, I would be eternally grateful.

UPDATE 2: I have attempted to modify layout_height in my activity_main.xml file, only to have it push the preview further down the screen, while it still retains it's 1:1 box format. Additionally, I have also considered implementing javaCameraView.getLayoutParams().height= in my MainActivity only to have it distort/stretch the camera preview and not achieve my intended desire.

解决方案

Ciao,

Short answer

I'm leaving at the end the full solution for the MainActivity class - both for the back and front cameras - after the code explanations


Full Details

I joined a few answers on this website and modified onCameraFrame(). Now I can open the app in portrait mode, as the native Android camera or Snapchat view

This solution is really lightweight, I didn't change any OpenCV file as in other answers on this website [e.g. this one]. Depending on the activeCamera you want to use [i.e. back or front one] there is a little modification required inside onCameraFrame(), which I will list below

Common base

So I first followed the 4 steps in this answer, exactly as they are presented there and they really put me on the right track. It is worth to notice that with these changes you will get immediately a good looking landscape view but as soon as you put your phone in a portrait position the upper and lower black bands will come back. Changing the line at step 3 into:

android:screenOrientation="portrait"

didn't solve for me. Also, if you want to go full screen you need to remove the title bar and in order to do so I incorporated this answer too. This means that you will need to modify also this line in the AndroidManifest.xml from the previous step 2

android:theme="@style/Theme.AppCompat.Light.NoActionBar.FullScreen"

Since you initialize the camera in two places and you need to change it [the current snippet works with the front camera, you need the back one] you can clean-up the code and start defining the camera of interest so that you can modify the input source in one point only:

public class MainActivity extends AppCompatActivity implements
        CameraBridgeViewBase.CvCameraViewListener2
{
    ...
    // back camera
    int activeCamera = CameraBridgeViewBase.CAMERA_ID_BACK;
    // front camera
    // int activeCamera = CameraBridgeViewBase.CAMERA_ID_FRONT;

then pass it to a new initializeCamera() method

private void initializeCamera(JavaCameraView javaCameraView, int activeCamera){
    javaCameraView.setCameraPermissionGranted();
    javaCameraView.setCameraIndex(activeCamera);
    javaCameraView.setVisibility(CameraBridgeViewBase.VISIBLE);
    javaCameraView.setCvCameraViewListener(this);
}

which you have to call as soon as Android detects that the user has given the CAMERA permission:

    if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
            == PackageManager.PERMISSION_GRANTED) {
        Log.d(TAG, "Permissions granted");
        initializeCamera(javaCameraView, activeCamera);

and:

    if (requestCode == MY_CAMERA_REQUEST_CODE) {
        if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            Toast.makeText(this, "Camera Permission granted", Toast.LENGTH_LONG).show();
            initializeCamera(javaCameraView, activeCamera);

Now it's the moment to distinguish between front and back camera

Back camera

In this case you won't need to manipulate the frames at all and the code goes as follows:

@Override
public void onCameraViewStarted(int width, int height){
}

@Override
public Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame inputFrame)
{
    mRGBA = inputFrame.rgba();
    return mRGBA;
}

Front camera

In this case you need to slightly manipulate the frames flipping them, otherwise your portrait mode will show upside down

@Override
public void onCameraViewStarted(int width, int height)
{
    mRGBAT = new Mat();
} 

@Override
public Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame inputFrame)
{
    mRGBA = inputFrame.rgba();
    // flipping to show portrait mode properly
    Core.flip(mRGBA, mRGBAT, 1);
    // releasing what's not anymore needed
    mRGBA.release();
    return mRGBAT;
}

Finally, be sure that the frame manipulations you add to your code are really required. Their processing time lowers performances and can even expose you to unrequired troubles. I didn't check accurately but I'm quite sure that transposing the matrices in your onCameraFrame() was the root cause for distortion


MainActivity for back camera

package com.change.package.name;

import android.Manifest;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.util.Log;
import android.view.WindowManager;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

import org.opencv.android.BaseLoaderCallback;
import org.opencv.android.CameraBridgeViewBase;
import org.opencv.android.JavaCameraView;
import org.opencv.android.OpenCVLoader;
import org.opencv.core.Core;
import org.opencv.core.Mat;

public class MainActivity extends AppCompatActivity implements
        CameraBridgeViewBase.CvCameraViewListener2
{
    private static String TAG = "MainActivity";
    JavaCameraView javaCameraView;
    Mat mRGBA;
    private static final int MY_CAMERA_REQUEST_CODE = 100;
    int activeCamera = CameraBridgeViewBase.CAMERA_ID_BACK;


    BaseLoaderCallback baseLoaderCallback = new BaseLoaderCallback(MainActivity.this) {
        @Override
        public void onManagerConnected(int status)
        {
            if (status == BaseLoaderCallback.SUCCESS) {
                javaCameraView.enableView();
            } else {
                super.onManagerConnected(status);
            }
        }
    };

    static
    {
        if (OpenCVLoader.initDebug())
        {
            Log.d(TAG, "OpenCV is Configured or Connected successfully.");
        }
        else
        {
            Log.d(TAG, "OpenCV not Working or Loaded.");
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        javaCameraView = (JavaCameraView) findViewById(R.id.my_camera_view);
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

        if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
                == PackageManager.PERMISSION_GRANTED) {
            Log.d(TAG, "Permissions granted");
            initializeCamera(javaCameraView, activeCamera);
        } else {
            Log.d(TAG, "Troubles");
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, MY_CAMERA_REQUEST_CODE);
            }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == MY_CAMERA_REQUEST_CODE) {
            if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                Toast.makeText(this, "Camera Permission granted", Toast.LENGTH_LONG).show();  
                initializeCamera(javaCameraView, activeCamera);
            } else {
                Toast.makeText(this, "Camera Permission denied", Toast.LENGTH_LONG).show();
            }
        }
    }

    private void initializeCamera(JavaCameraView javaCameraView, int activeCamera){
        javaCameraView.setCameraPermissionGranted();
        javaCameraView.setCameraIndex(activeCamera);

        javaCameraView.setVisibility(CameraBridgeViewBase.VISIBLE);
        javaCameraView.setCvCameraViewListener(this);
    }

    @Override
    public void onCameraViewStarted(int width, int height)
    {
    
    }

    @Override
    public void onCameraViewStopped()
    {
        mRGBA.release();
    }

    @Override
    public Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame inputFrame)
    {
        // code for the back camera
        mRGBA = inputFrame.rgba();
        return mRGBA;
    }

    @Override
    public void onPointerCaptureChanged(boolean hasCapture) {

    }    

    @Override
    protected void onDestroy() {
        super.onDestroy();

        if (javaCameraView != null)
        {
            javaCameraView.disableView();
        }
    }

    @Override
    protected void onPause() {
        super.onPause();

        if (javaCameraView != null)
        {
            javaCameraView.disableView();
        }
    }    

    @Override
    protected void onResume() {
        super.onResume();

        if (OpenCVLoader.initDebug())
        {
            Log.d(TAG, "OpenCV is Configured or Connected successfully.");
            baseLoaderCallback.onManagerConnected(BaseLoaderCallback.SUCCESS);
        }
        else
        {
            Log.d(TAG, "OpenCV not Working or Loaded.");
            OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION, this, baseLoaderCallback);
        }
    }
}

MainActivity for front camera

package com.change.package.name;

import android.Manifest;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.util.Log;
import android.view.WindowManager;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

import org.opencv.android.BaseLoaderCallback;
import org.opencv.android.CameraBridgeViewBase;
import org.opencv.android.JavaCameraView;
import org.opencv.android.OpenCVLoader;
import org.opencv.core.Core;
import org.opencv.core.Mat;

public class MainActivity extends AppCompatActivity implements
        CameraBridgeViewBase.CvCameraViewListener2
{
    private static String TAG = "MainActivity";
    JavaCameraView javaCameraView;
    Mat mRGBA, mRGBAT;
    private static final int MY_CAMERA_REQUEST_CODE = 100;
    int activeCamera = CameraBridgeViewBase.CAMERA_ID_FRONT;


    BaseLoaderCallback baseLoaderCallback = new BaseLoaderCallback(MainActivity.this) {
        @Override
        public void onManagerConnected(int status)
        {
            if (status == BaseLoaderCallback.SUCCESS) {
                javaCameraView.enableView();
            } else {
                super.onManagerConnected(status);
            }
        }
    };

    static
    {
        if (OpenCVLoader.initDebug())
        {
            Log.d(TAG, "OpenCV is Configured or Connected successfully.");
        }
        else
        {
            Log.d(TAG, "OpenCV not Working or Loaded.");
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        javaCameraView = (JavaCameraView) findViewById(R.id.my_camera_view);
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

        if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
                == PackageManager.PERMISSION_GRANTED) {
            Log.d(TAG, "Permissions granted");
            initializeCamera(javaCameraView, activeCamera);
        } else {
            Log.d(TAG, "Troubles");
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, MY_CAMERA_REQUEST_CODE);
            }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == MY_CAMERA_REQUEST_CODE) {
            if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                Toast.makeText(this, "Camera Permission granted", Toast.LENGTH_LONG).show();
                initializeCamera(javaCameraView, activeCamera);
            } else {
                Toast.makeText(this, "Camera Permission denied", Toast.LENGTH_LONG).show();
            }
        }
    }

    private void initializeCamera(JavaCameraView javaCameraView, int activeCamera){
        javaCameraView.setCameraPermissionGranted();
        javaCameraView.setCameraIndex(activeCamera);   
        javaCameraView.setVisibility(CameraBridgeViewBase.VISIBLE);
        javaCameraView.setCvCameraViewListener(this);
    }

    @Override
    public void onCameraViewStarted(int width, int height)
    {
        mRGBAT = new Mat();
    }

    @Override
    public void onCameraViewStopped()
    {
        mRGBA.release();
    }

    @Override
    public Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame inputFrame)
    {
        // code for the front camera
        mRGBA = inputFrame.rgba();
        // flipping to show portrait mode properly
        Core.flip(mRGBA, mRGBAT, 1);
        mRGBA.release();
        return mRGBAT;
    }

    @Override
    public void onPointerCaptureChanged(boolean hasCapture) {

    }    

    @Override
    protected void onDestroy() {
        super.onDestroy();

        if (javaCameraView != null)
        {
            javaCameraView.disableView();
        }
    }

    @Override
    protected void onPause() {
        super.onPause();

        if (javaCameraView != null)
        {
            javaCameraView.disableView();
        }
    }    

    @Override
    protected void onResume() {
        super.onResume();

        if (OpenCVLoader.initDebug())
        {
            Log.d(TAG, "OpenCV is Configured or Connected successfully.");
            baseLoaderCallback.onManagerConnected(BaseLoaderCallback.SUCCESS);
        }
        else
        {
            Log.d(TAG, "OpenCV not Working or Loaded.");
            OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION, this, baseLoaderCallback);
        }
    }
}

Have a good day,
Antonino

这篇关于OpenCV-如何在Android中设置全屏摄像头视图?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆