OpenCV-如何在Android中设置全屏摄像头视图? [英] OpenCV - How to set a Full Screen Camera view in 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屋!