当前位置: 首页 > news >正文

Android Camera2开启电子防抖(EIS)和光学防抖(OIS)

刚好当前项目有录像功能,使用了第三方框架是基于Camera2引擎开发,当使用 Camera2 API 开发相机应用时,启用和关闭 EIS(电子防抖)是一个重要的功能。EIS 可以帮助减少相机拍摄时的抖动,从而提高图像和视频的稳定性;OIS是光学图片想稳定器,功能是通过镜头的浮动透镜来纠正“光轴偏移”,需要硬件的支持,两者同时开启在录像时效果更佳。

EIS原理:

使用CCD偏移来实现防抖,通过降低图像失真和抖动,从而提高图像质量,首先把CCD安置在一个可以上下左右移动的支架上,然后当陀螺传感器检测到抖动的时候,就会把抖动的方向、速度和移动量等参数经过处理,计算出足以抵消抖动的CCD移动量,简单说就是通过放大录像焦距,根据陀螺仪旋转时预留周边的视角通过进行补帧移动画面给人感觉没有那么抖动,但效果没有光学防抖的好。

OIS原理:

其原理是通过镜头内的陀螺仪侦测到微小的移动,然后将信号传至微处理器,处理器立即计算需要补偿的位移量,然后通过补偿镜片组,根据镜头的抖动方向及位移量加以补偿。

对比开启EIS和OIS的摄像对比

eis开

eis关

1. 检查设备支持的特性

在使用 Camera2 API 开启 EIS 之前,我们需要首先检查设备是否支持 EIS 特性。我们可以通过 CameraCharacteristics 类来获取相机设备的特性信息。

 CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);CameraCharacteristics characteristics = manager.getCameraCharacteristics(mCameraDevice.getId());boolean isModeHaveStabilization = false; // 支持电子防抖final int[] availableVideoStabilization = characteristics.get(CameraCharacteristics.CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES);if (availableVideoStabilization == null || availableVideoStabilization.length == 0) {Log.e(TAG, "Optical stabilization not available");return;}for (int mode : availableVideoStabilization) {if (mode == CaptureRequest.CONTROL_VIDEO_STABILIZATION_MODE_ON) {isModeHaveStabilization = true;Log.d(TAG, "Using video stabilization.");break;}}int[] stabilizationModes = characteristics.get(CameraCharacteristics.LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION);if (stabilizationModes == null || stabilizationModes.length == 0) {Log.e(TAG, "Optical stabilization not available");return;}for (int mode : stabilizationModes) {if (mode == CaptureRequest.LENS_OPTICAL_STABILIZATION_MODE_ON) {isModeSupported = true;   // 支持光学防抖break;}}
2. 启用 EIS和关闭EIS

记得判断是否支持EIS

// 开启EIS
mPreviewBuilder.set(CaptureRequest.CONTROL_VIDEO_STABILIZATION_MODE, CaptureRequest.CONTROL_VIDEO_STABILIZATION_MODE_ON);//关闭EIS
mPreviewBuilder.set(CaptureRequest.CONTROL_VIDEO_STABILIZATION_MODE, CaptureRequest.CONTROL_VIDEO_STABILIZATION_MODE_OFF);
3. 启用OIS和关闭OIS
 captureRequestBuilder.set(CaptureRequest.LENS_OPTICAL_STABILIZATION_MODE,mEisEnabled ? CaptureRequest.LENS_OPTICAL_STABILIZATION_MODE_ON :CaptureRequest.LENS_OPTICAL_STABILIZATION_MODE_OFF);

在创建预览请求的时候注意一定要设置成录制模式,预览模式开启不了EIS,设置无效

mPreviewBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);

下面时完整代码片段,希望可以帮助到有需要的人

public class Camera2Activity extends AppCompatActivity {private static final String TAG = "Camera2Example";private TextureView mTextureView;private CameraDevice mCameraDevice;private CaptureRequest.Builder mPreviewBuilder;private CameraCaptureSession mCaptureSession;// private SurfaceTexture mSurfaceTexture;private Button captureModel;//private Camera2Helper mCamera2Helper;boolean mEisEnabled = true;private Handler backgroundHandler;private HandlerThread backgroundThread;@SuppressLint("MissingInflatedId")@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_camera);initView();}private void initView() {captureModel = (Button) findViewById(R.id.captureModel);mTextureView = findViewById(R.id.textureView);mCaptureButton = findViewById(R.id.captureButton);if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO, Manifest.permission.CAMERA}, 200);return;}findViewById(R.id.eisopen).setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {enableEis();}});findViewById(R.id.eisclose).setOnClickListener(v -> {disableEis();});captureModel.setOnClickListener(v -> {switchMode();});}private TextureView.SurfaceTextureListener textureListener = new TextureView.SurfaceTextureListener() {@Overridepublic void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {openCamera();}@Overridepublic void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {}@Overridepublic boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {return false;}@Overridepublic void onSurfaceTextureUpdated(SurfaceTexture surface) {}};//打开相机public void openCamera() {CameraManager cameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);try {String cameraId = cameraManager.getCameraIdList()[0];if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {// 请求权限ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, 200);return;}cameraManager.openCamera(cameraId, new CameraDevice.StateCallback() {@Overridepublic void onOpened(@NonNull CameraDevice camera) {mCameraDevice = camera;createCameraPreviewSession();}@Overridepublic void onDisconnected(@NonNull CameraDevice camera) {mCameraDevice.close();mCameraDevice = null;}@Overridepublic void onError(@NonNull CameraDevice camera, int error) {mCameraDevice.close();mCameraDevice = null;}}, null);} catch (CameraAccessException e) {e.printStackTrace();}}// 创建CameraCaptureSessionprivate void createCameraPreviewSession() {try {SurfaceTexture texture = mTextureView.getSurfaceTexture();// 设置预览尺寸texture.setDefaultBufferSize(mTextureView.getWidth(), mTextureView.getHeight());assert texture != null;// 创建预览SurfaceSurface surface = new Surface(texture);// 创建CaptureRequest.BuildermPreviewBuilder = mCameraDevice.createCaptureRequest(mCurrentMode);// 设置自动对焦模式mPreviewBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);// 设置自动曝光模式mPreviewBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);mPreviewBuilder.addTarget(surface);toggleStabilization(mPreviewBuilder);// 创建CameraCaptureSessionmCameraDevice.createCaptureSession(Collections.singletonList(surface),new CameraCaptureSession.StateCallback() {@Overridepublic void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) {// 相机已经关闭if (null == mCameraDevice) {return;}// 会话准备好后,我们开始显示预览mCaptureSession = cameraCaptureSession;updatePreview();}@Overridepublic void onConfigureFailed(@NonNull CameraCaptureSession cameraCaptureSession) {//   showToast("Failed");}}, backgroundHandler);} catch (CameraAccessException e) {e.printStackTrace();}}int mCurrentMode = CameraDevice.TEMPLATE_PREVIEW;// 在点击按钮时切换模式private void switchMode() {if (mCurrentMode == CameraDevice.TEMPLATE_PREVIEW) {// 切换到录制模式mCurrentMode = CameraDevice.TEMPLATE_RECORD;createCameraPreviewSession();captureModel.setText("切换到预览模式");} else {// 切换到预览模式mPreviewBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_CANCEL);mCurrentMode = CameraDevice.TEMPLATE_PREVIEW;createCameraPreviewSession();captureModel.setText("切换到录制模式");}}// 电子防抖和光学防抖private void toggleStabilization(CaptureRequest.Builder captureRequestBuilder) {if (mPreviewBuilder == null) {return;}try {CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);CameraCharacteristics characteristics = manager.getCameraCharacteristics(mCameraDevice.getId());boolean isModeHaveStabilization = false; // 支持电子防抖boolean isModeSupported = false; // 支持光学防抖final int[] availableVideoStabilization = characteristics.get(CameraCharacteristics.CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES);if (availableVideoStabilization == null || availableVideoStabilization.length == 0) {Log.e(TAG, "Optical stabilization not available");return;}for (int mode : availableVideoStabilization) {if (mode == CaptureRequest.CONTROL_VIDEO_STABILIZATION_MODE_ON) {isModeHaveStabilization = true;Log.d(TAG, "Using video stabilization.");break;}}// 开启EIS电子防抖功能if (mEisEnabled && isModeHaveStabilization) {mPreviewBuilder.set(CaptureRequest.CONTROL_VIDEO_STABILIZATION_MODE, CaptureRequest.CONTROL_VIDEO_STABILIZATION_MODE_ON);mPreviewBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_USE_SCENE_MODE);mPreviewBuilder.set(CaptureRequest.CONTROL_SCENE_MODE, CameraMetadata.CONTROL_SCENE_MODE_ACTION); // hrd 动作场景模式} else {mPreviewBuilder.set(CaptureRequest.CONTROL_VIDEO_STABILIZATION_MODE, CaptureRequest.CONTROL_VIDEO_STABILIZATION_MODE_OFF);mPreviewBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_USE_SCENE_MODE);mPreviewBuilder.set(CaptureRequest.CONTROL_SCENE_MODE, CameraMetadata.CONTROL_SCENE_MODE_ACTION); // hrd  动作场景模式}int[] stabilizationModes = characteristics.get(CameraCharacteristics.LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION);if (stabilizationModes == null || stabilizationModes.length == 0) {Log.e(TAG, "Optical stabilization not available");return;}for (int mode : stabilizationModes) {if (mode == CaptureRequest.LENS_OPTICAL_STABILIZATION_MODE_ON) {isModeSupported = true;break;}}// 开启OIS光学防抖功能if (isModeSupported) {captureRequestBuilder.set(CaptureRequest.LENS_OPTICAL_STABILIZATION_MODE,mEisEnabled ? CaptureRequest.LENS_OPTICAL_STABILIZATION_MODE_ON :CaptureRequest.LENS_OPTICAL_STABILIZATION_MODE_OFF);}} catch (CameraAccessException e) {e.printStackTrace();}}// 更新预览private void updatePreview() {if (null == mCameraDevice) {return;}try {mCaptureSession.setRepeatingRequest(mPreviewBuilder.build(), null, backgroundHandler);} catch (CameraAccessException e) {e.printStackTrace();}}// 开启EIS电子防抖功能private void enableEis() {mEisEnabled = true;toggleStabilization(mPreviewBuilder);updatePreview();}// 关闭EIS电子防抖功能private void disableEis() {mEisEnabled = false;toggleStabilization(mPreviewBuilder);updatePreview();}@Overrideprotected void onResume() {super.onResume();startBackgroundThread();if (mTextureView.isAvailable()) {openCamera();} else {mTextureView.setSurfaceTextureListener(textureListener);}}@Overrideprotected void onPause() {super.onPause();stopBackgroundThread();closeCamera();}private void closeCamera() {if (mCaptureSession != null) {mCaptureSession.close();mCaptureSession = null;}if (mCameraDevice != null) {mCameraDevice.close();mCameraDevice = null;}}private void startBackgroundThread() {backgroundThread = new HandlerThread("CameraBackground");backgroundThread.start();backgroundHandler = new Handler(backgroundThread.getLooper());}private void stopBackgroundThread() {backgroundThread.quitSafely();try {backgroundThread.join();backgroundThread = null;backgroundHandler = null;} catch (InterruptedException e) {e.printStackTrace();}}
}

相关文章:

Android Camera2开启电子防抖(EIS)和光学防抖(OIS)

刚好当前项目有录像功能,使用了第三方框架是基于Camera2引擎开发,当使用 Camera2 API 开发相机应用时,启用和关闭 EIS(电子防抖)是一个重要的功能。EIS 可以帮助减少相机拍摄时的抖动,从而提高图像和视频的…...

劲爆:Sam Altman 回归CEO专访确认Q*的存在

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗?订阅我们的简报,深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同,从行业内部的深度分析和实用指南中受益。不要错过这个机会,成为AI领…...

Electronica慕尼黑电子展 Samtec团队与21ic分享虎家产品与方案

【摘要/前言】 “希望但凡是能够使用到连接器的场合都有Samtec的身影” 在慕尼黑上海电子展现场,Samtec华东区销售经理章桢彦先生在与21ic副主编刘岩轩老师的采访中,如是说道。这是一种愿景,更是Samtec的努力方向。短短一句话,…...

Vue基本使用(一)

📑前言 本文主要是【Vue】——Vue基本使用的文章,如果有什么需要改进的地方还请大佬指出⛺️ 🎬作者简介:大家好,我是听风与他🥇 ☁️博客首页:CSDN主页听风与他 🌄每日一句&#x…...

Android:BackStackRecord

BackStackRecord:fragment回退栈,继承自FragmentTransaction,并且实现了OpGenerator接口,OpGenerator接口用来添加或弹出事务的,后面会提到。 从《Android:从源码看FragmentManager如何工作》文章知道,每次beginTransaction会创建一个BackStackRecord对象,改对象持有f…...

微信小程序 slider 翻转最大和最小值

微信小程序 slider 翻转最大和最小值 场景代码示例index.wxmlindex.jsutil.js 参考资料 场景 我想使用 slider 时最左边是 10 最右是 -10。 但是想当然的直接改成<slider min"10" max"-10" step"1" /> 并没用。 查了文档和社区也没有现成…...

APITable免费开源的多维表格与可视化数据库本地部署公网远程访问

APITable免费开源的多维表格与可视化数据库公网远程访问 文章目录 APITable免费开源的多维表格与可视化数据库公网远程访问前言1. 部署APITable2. cpolar的安装和注册3. 配置APITable公网访问地址4. 固定APITable公网地址 前言 vika维格表作为新一代数据生产力平台&#xff0c…...

配电房综合监控系统

配电房综合监控系统是一种集成了实时监控、数据采集、远程控制等多功能的系统&#xff0c;用于对配电房进行全方位的监测和管理。 力安科技配电室综合监控系统依托电易云-智慧电力物联网&#xff0c;实现配电室环境监测、有害气体监测、安防监控、采暖通风、门禁、灯光、风机、…...

【JavaSE】集合(学习笔记)

一、数据结构 1、栈 压栈 / 弹栈栈顶元素、栈底元素先进后出 2、队列 入队列 / 出队列前端、后端先进先出 3、数组 查询效率高&#xff0c;增删效率低 4、链表 查询效率低(必须从头找)&#xff0c;增删效率高 5、哈希表 比较方法哈希值equals结构&#xff1a;数组 链…...

Mybatis 的简单运用介绍

Mybatis 用于操作数据库 操作数据库肯定需要: 1.SQL语句 2.数据库对象和 java 对象的映射 接下来我们看看怎么使用 Mybatis 我们先搞一些数据库内容 然后将其这些内容和Java对象进行映射 再创建一个类实现 select * from 再写一个类证明上述代码是否可以实现 别忘了在appli…...

python的itertools库

itertools常用的方法如下&#xff1a; import itertools 1. 生成的列表累加&#xff0c;在生成新的列表x itertools.accumulate(range(10))print(list(x))结果&#xff1a;[0, 1, 3, 6, 10, 15, 21, 28, 36, 45] 2. 连接多个列表或者迭代器x itertools.chain(range(3), rang…...

STM32/GD32_分散加载

Q&#xff1a;如何将一个变量、某个源文件的函数在编译阶段就存储在用户指定的区域&#xff1f; KEIL环境&#xff1a;.map后缀文件、.sct后缀文件 IAR环境&#xff1a;.map后缀文件、.icf后缀文件 【map文件】 对固件里面的变量、函数、常量等元素的存储空间进行分配的说明…...

go clean

移除目标文件和缓存文件。 更多信息&#xff1a;https://golang.org/cmd/go/#hdr-Remove_object_files_and_cached_files. 只打印移除命令&#xff0c;而不会真正移除任何东西&#xff1a; go clean -n 删除编译缓存&#xff1a; go clean -cache 删除所有测试结果缓存&…...

BUUCTF [ACTF新生赛2020]swp 1

BUUCTF:https://buuoj.cn/challenges 题目描述&#xff1a; 得到的 flag 请包上 flag{} 提交。 密文&#xff1a; 下载附件&#xff0c;得到一个.tar文件。 解题思路&#xff1a; 1、使用WinRAR解压.tar文件&#xff0c;得到两个.zip文件。 解压wget.zip文件&#xff0c;得…...

【PTA题目】7-4 缩写期刊名 分数 10

7-4 缩写期刊名 分数 10 全屏浏览题目 切换布局 作者 黄龙军 单位 绍兴文理学院 科研工作者经常要向不同的期刊投稿。但不同期刊的参考文献的格式往往各不相同。有些期刊要求参考文献所发表的期刊名必须采用缩写形式&#xff0c;否则直接拒稿。现对于给定的期刊名&#xff…...

什么是 TLS/SSL 握手

TLS/SSL 握手是一个加密过程&#xff0c;每当客户端&#xff08;如浏览器&#xff09;与服务器建立连接时&#xff0c;都会在后台进行&#xff0c;此握手协议有助于客户端和服务器之间的安全连接&#xff0c;从而促进隐私、数据完整性和机密性。 TLS/SSL 握手何时发生 每当客…...

和鲸科技与国科环宇建立战略合作伙伴关系,以软硬件一体化解决方案促进科技创新

近日&#xff0c;在国科环宇土星云算力服务器产品发布会暨合作伙伴年度会上&#xff0c;和鲸科技与国科环宇正式完成战略伙伴签约仪式&#xff0c;宣布达成战略合作伙伴关系。未来&#xff0c;双方将深化合作&#xff0c;充分发挥在产品和市场方面的互补优势&#xff0c;为企事…...

[C++]六大默认成员函数详解

☃️个人主页&#xff1a;fighting小泽 &#x1f338;作者简介&#xff1a;目前正在学习C和Linux &#x1f33c;博客专栏&#xff1a;C入门 &#x1f3f5;️欢迎关注&#xff1a;评论&#x1f44a;&#x1f3fb;点赞&#x1f44d;&#x1f3fb;留言&#x1f4aa;&#x1f3fb; …...

组合(回溯算法)

77. 组合 - 力扣&#xff08;LeetCode&#xff09; 题目描述 给定两个整数 n 和 k&#xff0c;返回范围 [1, n] 中所有可能的 k 个数的组合。 你可以按 任何顺序 返回答案。 样例输入 示例 1&#xff1a; 输入&#xff1a;n 4, k 2 输出&#xff1a; [[2,4],[3,4],[2,3],…...

力扣:1419. 数青蛙

题目&#xff1a; 代码&#xff1a; class Solution { public:int minNumberOfFrogs(string croakOfFrogs){string s "croak";int ns.size();//首先创建一个哈希表来标明每个元素出现的次数&#xff01;vector<int>hash(n); //不用真的创建一个hash表用一个数…...

docker详细操作--未完待续

docker介绍 docker官网: Docker&#xff1a;加速容器应用程序开发 harbor官网&#xff1a;Harbor - Harbor 中文 使用docker加速器: Docker镜像极速下载服务 - 毫秒镜像 是什么 Docker 是一种开源的容器化平台&#xff0c;用于将应用程序及其依赖项&#xff08;如库、运行时环…...

Module Federation 和 Native Federation 的比较

前言 Module Federation 是 Webpack 5 引入的微前端架构方案&#xff0c;允许不同独立构建的应用在运行时动态共享模块。 Native Federation 是 Angular 官方基于 Module Federation 理念实现的专为 Angular 优化的微前端方案。 概念解析 Module Federation (模块联邦) Modul…...

根据万维钢·精英日课6的内容,使用AI(2025)可以参考以下方法:

根据万维钢精英日课6的内容&#xff0c;使用AI&#xff08;2025&#xff09;可以参考以下方法&#xff1a; 四个洞见 模型已经比人聪明&#xff1a;以ChatGPT o3为代表的AI非常强大&#xff0c;能运用高级理论解释道理、引用最新学术论文&#xff0c;生成对顶尖科学家都有用的…...

使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台

🎯 使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台 📌 项目背景 随着大语言模型(LLM)的广泛应用,开发者常面临多个挑战: 各大模型(OpenAI、Claude、Gemini、Ollama)接口风格不统一;缺乏一个统一平台进行模型调用与测试;本地模型 Ollama 的集成与前…...

初学 pytest 记录

安装 pip install pytest用例可以是函数也可以是类中的方法 def test_func():print()class TestAdd: # def __init__(self): 在 pytest 中不可以使用__init__方法 # self.cc 12345 pytest.mark.api def test_str(self):res add(1, 2)assert res 12def test_int(self):r…...

深度学习习题2

1.如果增加神经网络的宽度&#xff0c;精确度会增加到一个特定阈值后&#xff0c;便开始降低。造成这一现象的可能原因是什么&#xff1f; A、即使增加卷积核的数量&#xff0c;只有少部分的核会被用作预测 B、当卷积核数量增加时&#xff0c;神经网络的预测能力会降低 C、当卷…...

SiFli 52把Imagie图片,Font字体资源放在指定位置,编译成指定img.bin和font.bin的问题

分区配置 (ptab.json) img 属性介绍&#xff1a; img 属性指定分区存放的 image 名称&#xff0c;指定的 image 名称必须是当前工程生成的 binary 。 如果 binary 有多个文件&#xff0c;则以 proj_name:binary_name 格式指定文件名&#xff0c; proj_name 为工程 名&…...

【Nginx】使用 Nginx+Lua 实现基于 IP 的访问频率限制

使用 NginxLua 实现基于 IP 的访问频率限制 在高并发场景下&#xff0c;限制某个 IP 的访问频率是非常重要的&#xff0c;可以有效防止恶意攻击或错误配置导致的服务宕机。以下是一个详细的实现方案&#xff0c;使用 Nginx 和 Lua 脚本结合 Redis 来实现基于 IP 的访问频率限制…...

FFmpeg:Windows系统小白安装及其使用

一、安装 1.访问官网 Download FFmpeg 2.点击版本目录 3.选择版本点击安装 注意这里选择的是【release buids】&#xff0c;注意左上角标题 例如我安装在目录 F:\FFmpeg 4.解压 5.添加环境变量 把你解压后的bin目录&#xff08;即exe所在文件夹&#xff09;加入系统变量…...

【Linux手册】探秘系统世界:从用户交互到硬件底层的全链路工作之旅

目录 前言 操作系统与驱动程序 是什么&#xff0c;为什么 怎么做 system call 用户操作接口 总结 前言 日常生活中&#xff0c;我们在使用电子设备时&#xff0c;我们所输入执行的每一条指令最终大多都会作用到硬件上&#xff0c;比如下载一款软件最终会下载到硬盘上&am…...