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

Android 使用Camera2 API 和 GLSurfaceView实现相机预览

GLSurfaceView 和 SurfaceView 是 Android 中用于显示图像的两个视图类,它们在实现方式和使用场景上有一些区别。

  • 实现方式:GLSurfaceView 基于 OpenGL ES 技术实现,可以通过 OpenGL ES 渲染图像。而 SurfaceView 则是通过基于线程的绘制方式,可以在独立的线程中进行绘制操作。
  • 性能:由于 GLSurfaceView 使用了 OpenGL ES 技术,可以充分利用 GPU 进行图像渲染,因此在处理复杂图像和动画时通常具有更好的性能。相比之下,SurfaceView 使用 CPU 进行图像绘制,性能可能相对较低。
  • 使用场景:如果你需要进行复杂的图形绘制、图像处理或者动画,那么 GLSurfaceView 是一个更好的选择,因为它提供了强大的 OpenGL ES 功能支持。另外,GLSurfaceView 还可以与其他 OpenGL ES 相关的库和工具进行集成。而 SurfaceView 在一些简单的图像展示场景中更常见,例如显示图片、播放视频等。
  • 使用复杂度:由于 GLSurfaceView 使用了 OpenGL ES,因此它需要编写着色器程序来进行图像渲染,并且需要处理 OpenGL ES 相关的上下文管理。相对而言,SurfaceView 的使用相对简单,只需继承 SurfaceView 类并实现自定义的绘制逻辑即可。

需要注意的是,由于 GLSurfaceView 使用了 OpenGL ES 技术,它对开发者的要求更高,需要熟悉 OpenGL ES 相关的知识和编程技术。而 SurfaceView 在一些简单的场景中更易于使用和理解。

总之,GLSurfaceView 适用于需要进行复杂图形渲染和动画的场景,而 SurfaceView 适用于一般的图像展示和简单的绘制需求。选择哪个类取决于你的具体需求和技术能力。

  1. 在 AndroidManifest.xml 文件中添加相机权限:

    <uses-permission android:name="android.permission.CAMERA" />
    
  2. 创建相机预览的布局

     <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=".CameraActivity"><android.opengl.GLSurfaceViewandroid:id="@+id/glsurfaceview"android:layout_width="match_parent"android:layout_height="match_parent" />
    </RelativeLayout>
    
  3. 创建相机预览的 Activity,用于管理相机预览和 OpenGL 绘制、

     package com.test.jnitestimport android.Manifestimport android.content.Contextimport android.content.pm.PackageManagerimport android.graphics.SurfaceTextureimport android.hardware.camera2.CameraCaptureSessionimport android.hardware.camera2.CameraDeviceimport android.hardware.camera2.CameraManagerimport android.hardware.camera2.CaptureRequestimport android.opengl.GLSurfaceViewimport android.os.Bundleimport android.util.Sizeimport android.view.Surfaceimport android.view.WindowManagerimport androidx.appcompat.app.AppCompatActivityimport androidx.core.app.ActivityCompatimport com.test.jnitest.databinding.ActivityCameraBindingimport java.util.*class CameraActivity : AppCompatActivity() {var mGLSurfaceView:GLSurfaceView?=nullvar mRenderer:CameraRenderer?=nullvar cameraManager:CameraManager?=nullvar mCameraDevice:CameraDevice?=nullvar mCaptureSession:CameraCaptureSession?=nullvar mRequestBuild:CaptureRequest.Builder?=nullvar size = Size(1920,1080)lateinit var mContext:Contextlateinit var binding:ActivityCameraBindingoverride fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)binding = ActivityCameraBinding.inflate(layoutInflater)setContentView(binding.root)// 设置状态栏透明window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS)//设置导航栏透明window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION)mContext = thismGLSurfaceView = binding.glsurfaceviewmGLSurfaceView?.setEGLContextClientVersion(2)// 创建并设置相机渲染器mRenderer = CameraRenderer(mGLSurfaceView!!)mGLSurfaceView?.setRenderer(mRenderer)mGLSurfaceView?.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);// 获取摄像头管理器cameraManager = getSystemService(Context.CAMERA_SERVICE) as CameraManagerif (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {this.requestPermissions(mutableListOf<String>(Manifest.permission.CAMERA).toTypedArray(),200)return}cameraManager?.openCamera("5",mCameraStateCallback,null)}override fun onResume() {super.onResume()mGLSurfaceView?.onResume()}override fun onDestroy() {super.onDestroy()closeCamera()}// 相机状态回调var mCameraStateCallback = object : CameraDevice.StateCallback() {override fun onOpened(p0: CameraDevice) {mCameraDevice = p0// 创建预览会话var surfaceTexture = mRenderer?.mSurfaceTexturesurfaceTexture?.setDefaultBufferSize(size.width,size.height)var surface = Surface(surfaceTexture)mRequestBuild = mCameraDevice?.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW)mRequestBuild?.addTarget(surface)val surfaces = Arrays.asList(surface)mCameraDevice?.createCaptureSession(surfaces,mCaptureCallback,null)}override fun onDisconnected(p0: CameraDevice) {p0.close()}override fun onError(p0: CameraDevice, p1: Int) {p0.close()}}// 捕获会话状态回调var mCaptureCallback = object : CameraCaptureSession.StateCallback() {override fun onConfigured(p0: CameraCaptureSession) {mCaptureSession = p0mRequestBuild?.build()?.let { mCaptureSession?.setRepeatingRequest(it,null,null) }}override fun onConfigureFailed(p0: CameraCaptureSession) {p0.close()mCaptureSession = null}}// 关闭相机private fun closeCamera() {mCaptureSession?.close()mCaptureSession = nullmCameraDevice?.close()mCameraDevice = null}}
    
  4. 创建相机渲染器,创建一个继承自 GLSurfaceView.Renderer 的类,用于实现 OpenGL 绘制和与相机交互的逻辑

     package com.test.jnitestimport android.content.Contextimport android.graphics.SurfaceTextureimport android.graphics.SurfaceTexture.OnFrameAvailableListenerimport android.opengl.GLES11Extimport android.opengl.GLES20import android.opengl.GLSurfaceViewimport java.nio.ByteBufferimport java.nio.ByteOrderimport java.nio.FloatBufferimport javax.microedition.khronos.egl.EGLConfigimport javax.microedition.khronos.opengles.GL10class CameraRenderer(var mGLSurfaceView: GLSurfaceView):GLSurfaceView.Renderer,OnFrameAvailableListener {//摄像头图像的纹理IDvar textureId:Int = 0var mSurfaceTexture:SurfaceTexture?=nullprivate val COORDS_PER_VERTEX = 2private val TEXTURE_COORDS_PER_VERTEX = 2//顶点着色器var vertexShaderCode = """attribute vec4 a_position;attribute vec2 a_textureCoord;varying vec2 v_textureCoord;void main() {gl_Position = a_position;v_textureCoord = a_textureCoord;}"""// 片段着色器var fragmentShaderCode = """#extension GL_OES_EGL_image_external : requireprecision mediump float;uniform samplerExternalOES u_texture;varying vec2 v_textureCoord;void main() {gl_FragColor = texture2D(u_texture, v_textureCoord);}"""//顶点坐标数据,表示预览图像的位置和大小。private val VERTEX_COORDS = floatArrayOf(-1.0f, -1.0f,1.0f, -1.0f,-1.0f, 1.0f,1.0f, 1.0f)//纹理坐标数据,表示摄像头图像在预览区域的映射关系。private val TEXTURE_COORDS = floatArrayOf(0f, 1f,1f, 1f,0f, 0f,1f, 0f)//着色器程序的IDprivate var programId = 0//顶点属性的句柄private var positionHandle = 0private var textureCoordHandle = 0init {textureId = createTexture()mSurfaceTexture = SurfaceTexture(textureId)mSurfaceTexture?.setOnFrameAvailableListener(this)}/*** 初始化OpenGL,并加载顶点着色器和片段着色器。通过编译和链接着色器,创建着色器程序,并获取顶点属性的句柄。*/override fun onSurfaceCreated(p0: GL10?, p1: EGLConfig?) {// 在此进行 OpenGL 环境初始化,如创建纹理、着色器程序等// 设置清空颜色缓冲区时的颜色值为黑色GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f)// 加载顶点着色器和片段着色器val vertexShader: Int = loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode)val fragmentShader: Int = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode)// 创建着色器程序并将顶点着色器和片段着色器绑定到该程序上programId = GLES20.glCreateProgram()GLES20.glAttachShader(programId, vertexShader)GLES20.glAttachShader(programId, fragmentShader)// 链接着色器程序并检查是否链接成功GLES20.glLinkProgram(programId)// 获取顶点坐标属性和纹理坐标属性的位置positionHandle = GLES20.glGetAttribLocation(programId, "a_position")textureCoordHandle = GLES20.glGetAttribLocation(programId, "a_textureCoord")// 使用着色器程序GLES20.glUseProgram(programId)}override fun onSurfaceChanged(p0: GL10?, p1: Int, p2: Int) {// 在此响应 GLSurfaceView 尺寸变化,如更新视口大小等GLES20.glViewport(0, 0, p1, p2);}/*** 绘制每一帧,在此进行实际的绘制操作,如清屏、绘制纹理等*/override fun onDrawFrame(p0: GL10?) {// 更新纹理图像mSurfaceTexture?.updateTexImage();// 清空颜色缓冲区GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);// 设置顶点坐标属性并启用GLES20.glVertexAttribPointer(positionHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, 0, floatBufferFromArray(VERTEX_COORDS));GLES20.glEnableVertexAttribArray(positionHandle);// 设置纹理坐标属性并启用GLES20.glVertexAttribPointer(textureCoordHandle, TEXTURE_COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, 0, floatBufferFromArray(TEXTURE_COORDS));GLES20.glEnableVertexAttribArray(textureCoordHandle);// 激活纹理单元0,并将当前纹理绑定到外部OES纹理目标GLES20.glActiveTexture(GLES20.GL_TEXTURE0);GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, textureId);// 绘制三角带的图元GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, VERTEX_COORDS.size / COORDS_PER_VERTEX);}/*** 创建摄像头纹理*/private fun createTexture(): Int {// 创建一个用于存储纹理ID的数组val textureIds = IntArray(1)// 生成一个纹理对象,并将纹理ID存储到数组中GLES20.glGenTextures(1, textureIds, 0)// 将当前纹理绑定到OpenGL ES的纹理目标(外部OES纹理)GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, textureIds[0])// 设置纹理S轴的包裹模式为GL_CLAMP_TO_EDGE,即超出边界的纹理坐标会被截取到边界上的纹素GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE)// 设置纹理T轴的包裹模式为GL_CLAMP_TO_EDGEGLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE)// 设置纹理缩小过滤器为GL_NEAREST,即使用最近邻采样的方式进行纹理缩小GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST)// 设置纹理放大过滤器为GL_NEARESTGLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST)return textureIds[0]}/*** 加载着色器,接受着色器类型和着色器代码作为参数,并将编译后的着色器对象的ID返回* @param type 着色器类型,如GLES20.GL_VERTEX_SHADER或GLES20.GL_FRAGMENT_SHADER* @param shaderCode 着色器代码* @return 着色器的ID*/private fun loadShader(type: Int, shaderCode: String): Int {// 创建一个新的着色器对象val shader = GLES20.glCreateShader(type)// 将着色器代码加载到着色器对象中GLES20.glShaderSource(shader, shaderCode)// 编译着色器GLES20.glCompileShader(shader)return shader}private fun floatBufferFromArray(array: FloatArray): FloatBuffer? {val byteBuffer: ByteBuffer = ByteBuffer.allocateDirect(array.size * 4)byteBuffer.order(ByteOrder.nativeOrder())val floatBuffer: FloatBuffer = byteBuffer.asFloatBuffer()floatBuffer.put(array)floatBuffer.position(0)return floatBuffer}override fun onFrameAvailable(p0: SurfaceTexture?) {// 当相机有新的帧可用时回调,可以在这里进行一些处理mGLSurfaceView.requestRender()}}
    

通过以上步骤,你可以实现使用 Camera2 API 和 GLSurfaceView 预览相机的功能。在 CameraActivity 中,我们通过 Camera2 API 打开相机并创建相机预览会话,然后将相机预览的 SurfaceTexture 传递给 CameraRenderer,在 CameraRenderer 的 onDrawFrame() 方法中绘制相机预览帧的纹理内容。

相关文章:

Android 使用Camera2 API 和 GLSurfaceView实现相机预览

GLSurfaceView 和 SurfaceView 是 Android 中用于显示图像的两个视图类&#xff0c;它们在实现方式和使用场景上有一些区别。 实现方式&#xff1a;GLSurfaceView 基于 OpenGL ES 技术实现&#xff0c;可以通过 OpenGL ES 渲染图像。而 SurfaceView 则是通过基于线程的绘制方式…...

说说IO多路复用

分析&回答 IO多路复用 I/O multiplexing 这里面的 multiplexing 指的其实是在单个线程通过记录跟踪每一个Sock(I/O流)的状态(对应空管塔里面的Fight progress strip槽)来同时管理多个I/O流。直白点说&#xff1a;多路指的是多个socket连接&#xff0c;复用指的是复用一个…...

mysql 锁解决的办法

可以查看锁的信息,TRX_MYSQL_THREAD_ID 为processlist的表中的会话id,用于kill select trx_id,trx_state,trx_started,trx_requested_lock_id,trx_wait_started,trx_weight,trx_mysql_thread_id,trx_query from innodb_trx 可以查看锁的模式&#xff0c;类型&#xff0c;锁的表…...

C++零碎记录(五)

9. 静态成员 ① 静态成员就是在成员变量和成员函数前加上关键字static&#xff0c;称为静态成员。 ② 静态成员分为&#xff1a; 1. 静态成员变量 --所有对象共享同一份数据 --在编译阶段分配内存 --类内声明&#xff0c;类外初始化 2. 静态成员函数 --所有对象共享同一个函数…...

玩转Mysql系列 - 第16篇:变量详解

这是Mysql系列第16篇。 环境&#xff1a;mysql5.7.25&#xff0c;cmd命令中进行演示。 代码中被[]包含的表示可选&#xff0c;|符号分开的表示可选其一。 我们在使用mysql的过程中&#xff0c;变量也会经常用到&#xff0c;比如查询系统的配置&#xff0c;可以通过查看系统变…...

Windows云服务器 PHP搭建网站外网无法访问的问题

前言&#xff1a;本人在华为云上租了一台windows的云主机&#xff0c;可以远程访问桌面的那种&#xff0c;然后想搭个网站&#xff0c;最开始想到的是IIS&#xff0c;测试了下用html的文件&#xff0c;没有问题。但是&#xff0c;php文件却不能用&#xff0c;因为少了PHP环境。…...

TuyaOS Sensor Hub组件介绍

文章目录 Sensor Hub 设计思想分层设计Sensor Hub 层(tdl)Sensor Driver 层(tdd) 传感数据元素类型抽象传感器采集策略 Sensor Hub 对上数据与接口数据结构1. 数据读取的触发模式2. 元素型数据订阅规则3. 数据就绪通知回调4. 传感设备信息 应用接口1. 创建传感器实例2. 启动传感…...

【实战】React17+React Hook+TS4 最佳实践,仿 Jira 企业级项目(总结展望篇)

文章目录 一、项目起航&#xff1a;项目初始化与配置二、React 与 Hook 应用&#xff1a;实现项目列表三、TS 应用&#xff1a;JS神助攻 - 强类型四、JWT、用户认证与异步请求五、CSS 其实很简单 - 用 CSS-in-JS 添加样式六、用户体验优化 - 加载中和错误状态处理七、Hook&…...

Leetcode.321 拼接最大数

题目链接 Leetcode.321 拼接最大数 hard 题目描述 给定长度分别为 m m m 和 n n n 的两个数组&#xff0c;其元素由 0 ∼ 9 0 \sim 9 0∼9 构成&#xff0c;表示两个自然数各位上的数字。现在从这两个数组中选出 k k k ( k ≤ m n ) (k \leq m n) (k≤mn) 个数字拼接成…...

数学建模竞赛常用代码总结-PythonMatlab

数学建模过程中有许多可复用的基础代码&#xff0c;在此对 python 以及 MATLAB 中常用代码进行简单总结&#xff0c;该总结会进行实时更新。 一、文件读取 python (pandas) 文件后缀名&#xff08;扩展名&#xff09;并不是必须的&#xff0c;其作用主要一方面是提示系统是用…...

在Ubuntu上安装CUDA和cuDNN以及验证安装步骤

在Ubuntu上安装CUDA和cuDNN以及验证安装步骤 本教程详细介绍了如何在Ubuntu操作系统上安装CUDA&#xff08;NVIDIA的并行计算平台&#xff09;和cuDNN&#xff08;深度神经网络库&#xff09;&#xff0c;以及如何验证安装是否成功。通过按照这些步骤操作&#xff0c;您将能够…...

SecureCRT ssh链接服务器

SecureCRT通过密钥进行SSH登录 说明&#xff1a; 一般的密码方式登录容易被密码暴力破解。所以一般我们会将 SSH 的端口设置为默认22以外的端口&#xff0c;或者禁用root账户登录。其实可以通过密钥登录这种方式来更好地保证安全。 密钥形式登录的原理是&#xff1a;利用密钥…...

linux之perf(3)top实时性能

Linux之perf(3)top实时性能 Author&#xff1a;Onceday Date&#xff1a;2023年9月3日 漫漫长路&#xff0c;才刚刚开始… 注&#xff1a;该文档内容采用了GPT4.0生成的回答&#xff0c;部分文本准确率可能存在问题。 参考文档: Tutorial - Perf Wiki (kernel.org)perf-to…...

【linux命令讲解大全】076.pgrep命令:查找和列出符合条件的进程ID

文章目录 pgrep补充说明语法选项参数实例 从零学 python pgrep 根据用户给出的信息在当前运行进程中查找并列出符合条件的进程ID&#xff08;PID&#xff09; 补充说明 pgrep 命令以名称为依据从运行进程队列中查找进程&#xff0c;并显示查找到的进程ID。每一个进程ID以一个…...

微信小程序开发---条件渲染和列表渲染

目录 一、条件渲染 &#xff08;1&#xff09;基本使用 &#xff08;2&#xff09;block &#xff08;3&#xff09;hidden 二、列表渲染 &#xff08;1&#xff09;基本使用 &#xff08;2&#xff09;手动指定索引和当前项的变量名 &#xff08;3&#xff09;wx:key的…...

【ES6】require、export和import的用法

在JavaScript中&#xff0c;require、export和import是Node.js的模块系统中的关键字&#xff0c;用于处理模块间的依赖关系。 1、require&#xff1a;这是Node.js中引入模块的方法。当你需要使用其他模块提供的功能时&#xff0c;可以使用require关键字来引入该模块。例如&…...

Vue + Element UI 前端篇(九):接口格式定义

接口请求格式定义 前台显示需要后台数据&#xff0c;我们这里先把前后端交互接口定义好&#xff0c;没有后台的时候&#xff0c;也方便用mock模拟。 接口定义遵循几个规范&#xff1a; 1. 接口按功能模块划分。 系统登录&#xff1a;登录相关接口 用户管理&#xff1a;用户…...

部署Django报错-requires SQLite 3.8.3 or higher

记一次CentOS7部署Django项目时的报错 问题出现 在部署测试环境时&#xff0c;有需要用到一个python的后端服务&#xff0c;要部署到测试环境中去 心想这不是so easy吗&#xff0c;把本地调试时使用的python版本及Django版本在服务器上对应下载好&#xff0c;然后直接执行命…...

什么是网络存储服务器

网络存储器就像一台只有存储功能的终端&#xff0c;独立地工作&#xff0c;里面带有固定的系统&#xff0c;但可以自己设置部分参数功能&#xff0c;可以接入服务器或者电脑进行设置&#xff0c;网络存储服务器实际上就是精简的、小型化的服务器&#xff0c;同样由主板、CPU&am…...

lv3 嵌入式开发-10 NFS服务器搭建及使用

目录 1 NFS服务器介绍 1.1 NFS服务器的介绍 1.2 NFS服务器的特点 1.3 NFS服务器的适用场景 2 NFS服务器搭建 2.1 配置介绍 2.2 常见错误 3 WINDOWS下NFS服务器搭建&#xff08;扩展&#xff09; 1 NFS服务器介绍 1.1 NFS服务器的介绍 nfs&#xff08;Network File Sys…...

第19节 Node.js Express 框架

Express 是一个为Node.js设计的web开发框架&#xff0c;它基于nodejs平台。 Express 简介 Express是一个简洁而灵活的node.js Web应用框架, 提供了一系列强大特性帮助你创建各种Web应用&#xff0c;和丰富的HTTP工具。 使用Express可以快速地搭建一个完整功能的网站。 Expre…...

零门槛NAS搭建:WinNAS如何让普通电脑秒变私有云?

一、核心优势&#xff1a;专为Windows用户设计的极简NAS WinNAS由深圳耘想存储科技开发&#xff0c;是一款收费低廉但功能全面的Windows NAS工具&#xff0c;主打“无学习成本部署” 。与其他NAS软件相比&#xff0c;其优势在于&#xff1a; 无需硬件改造&#xff1a;将任意W…...

理解 MCP 工作流:使用 Ollama 和 LangChain 构建本地 MCP 客户端

&#x1f31f; 什么是 MCP&#xff1f; 模型控制协议 (MCP) 是一种创新的协议&#xff0c;旨在无缝连接 AI 模型与应用程序。 MCP 是一个开源协议&#xff0c;它标准化了我们的 LLM 应用程序连接所需工具和数据源并与之协作的方式。 可以把它想象成你的 AI 模型 和想要使用它…...

数据链路层的主要功能是什么

数据链路层&#xff08;OSI模型第2层&#xff09;的核心功能是在相邻网络节点&#xff08;如交换机、主机&#xff09;间提供可靠的数据帧传输服务&#xff0c;主要职责包括&#xff1a; &#x1f511; 核心功能详解&#xff1a; 帧封装与解封装 封装&#xff1a; 将网络层下发…...

浅谈不同二分算法的查找情况

二分算法原理比较简单&#xff0c;但是实际的算法模板却有很多&#xff0c;这一切都源于二分查找问题中的复杂情况和二分算法的边界处理&#xff0c;以下是博主对一些二分算法查找的情况分析。 需要说明的是&#xff0c;以下二分算法都是基于有序序列为升序有序的情况&#xf…...

华硕a豆14 Air香氛版,美学与科技的馨香融合

在快节奏的现代生活中&#xff0c;我们渴望一个能激发创想、愉悦感官的工作与生活伙伴&#xff0c;它不仅是冰冷的科技工具&#xff0c;更能触动我们内心深处的细腻情感。正是在这样的期许下&#xff0c;华硕a豆14 Air香氛版翩然而至&#xff0c;它以一种前所未有的方式&#x…...

安宝特方案丨船舶智造的“AR+AI+作业标准化管理解决方案”(装配)

船舶制造装配管理现状&#xff1a;装配工作依赖人工经验&#xff0c;装配工人凭借长期实践积累的操作技巧完成零部件组装。企业通常制定了装配作业指导书&#xff0c;但在实际执行中&#xff0c;工人对指导书的理解和遵循程度参差不齐。 船舶装配过程中的挑战与需求 挑战 (1…...

push [特殊字符] present

push &#x1f19a; present 前言present和dismiss特点代码演示 push和pop特点代码演示 前言 在 iOS 开发中&#xff0c;push 和 present 是两种不同的视图控制器切换方式&#xff0c;它们有着显著的区别。 present和dismiss 特点 在当前控制器上方新建视图层级需要手动调用…...

【Linux系统】Linux环境变量:系统配置的隐形指挥官

。# Linux系列 文章目录 前言一、环境变量的概念二、常见的环境变量三、环境变量特点及其相关指令3.1 环境变量的全局性3.2、环境变量的生命周期 四、环境变量的组织方式五、C语言对环境变量的操作5.1 设置环境变量&#xff1a;setenv5.2 删除环境变量:unsetenv5.3 遍历所有环境…...

pgsql:还原数据库后出现重复序列导致“more than one owned sequence found“报错问题的解决

问题&#xff1a; pgsql数据库通过备份数据库文件进行还原时&#xff0c;如果表中有自增序列&#xff0c;还原后可能会出现重复的序列&#xff0c;此时若向表中插入新行时会出现“more than one owned sequence found”的报错提示。 点击菜单“其它”-》“序列”&#xff0c;…...