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

NDK OpenGL渲染画面效果

NDK系列之OpenGL渲染画面效果技术实战,本节主要是通过OpenGL Java库(谷歌对OpenGL C++库做了JIN封装,核心实现还是在Native层),实现页面渲染,自定义渲染特效。

实现效果:

实现逻辑:

1.创建Camera,绑定SurfaceTexture纹理画布对象;

2.将Camera预览画面数据传递给SurfaceTexture,缓存到buffer;

3.OpenGLES获取SurfaceTexture缓存的画面数据,渲染到GLSurfaceView(屏幕)。

本节主要内容:

1.OpenGL理论知识;

2.自定义GLSurfaceView;

3.自定义渲染器Renderer;

4.ScreenFilter封装OpenGL;

5.着色器代码工作。

源码:

NdkOpenGLPlay: NDK OpenGL渲染画面效果

一、OpenGL理论知识

1)图形领域的工业标准,是一套跨编程语言、跨平台的、专业的图形编程(软件)接口。它用于二维、三维图 像,是一个功能强大,调用方便的底层图形库。 可以简单理解为是GPU显卡语言。针对手机、PDA和游戏主机等嵌入式设备而设计的OpenGL API 子集, GLSurfaceView(不仅仅有,SurfaceView的所有功能,还拥有了 OpenGL的处理)。

2)OpenGL绘制流程:

为什么是三角形:三角形是 图像领域最小单元

1.位置排版,顶点位置确定好【顶点位置】

2.根据各个的位置排版,细节的网格排版【光栅化】

3.根据各个的位置排版,细节的网格排版执行逻辑处理【光栅操作逻辑】

4.颜色色彩的准备工作【纹理过滤】

5.片元处理,其实就是上色,绘制成效画面【纹理填充】

6.输出结果 ---> GPU 人类就看到了画面

3)Shader着色器(重点)

着色器(Shader)是运行在GPU上的小程序。

顶点着色器(vertex shader)如何处理顶点、法线等数据的小程序。

片元着色器(fragment shader)如何处理光、阴影、遮挡、环境等等对物体表面的影响,最终生成一 副图像的小程序。

二、自定义GLSurfaceView

GLSurfaceView继承至SurfaceView,不仅仅有SurfaceView的所有功能,还拥有了OpenGL的处理;而MyGLSurfaceView继承至GLSurfaceView,拥有GLSurfaceView的所有能力,支持自定义渲染器(render),可以灵活的进行OpenGL渲染。

public class MyGLSurfaceView extends GLSurfaceView {public MyGLSurfaceView(Context context, AttributeSet attrs) {super(context, attrs);init();}private void init() {// TODO 一:设置EGL版本// 2 代表是 OpenGLES 2.0setEGLContextClientVersion(2);// TODO 二:设置渲染器// 注意:// EGL 开启一个 GLThread.start  run { Renderer.onSurfaceCreated ...onSurfaceChanged  onDrawFrame }// 如果这三个函数,不让GLThread调用,会崩溃,所以他内部的设计,必须通过GLThread调用来调用三个函数setRenderer(new MyGlRenderer(this)); // this 自定义渲染器 会回调回来做处理,所有传递this// TODO 三:设置渲染器模式// RENDERMODE_WHEN_DIRTY 按需渲染,有帧数据的时候,才会去渲染( 效率高,麻烦,后面需要手动调用一次才行)// RENDERMODE_CONTINUOUSLY 每隔16毫秒,读取更新一次,(如果没有显示上一帧)setRenderMode(RENDERMODE_WHEN_DIRTY); // 手动模式 - 效率高,麻烦,后面需要手动调用一次才行}
}

三、自定义渲染器Renderer

1.实现GLSurfaceView.Renderer接口,实现接口的onSurfaceCreated()、onSurfaceChanged()和onDrawFrame()方法;

1)当Surface创建时,回调onSurfaceCreated()函数,创建CameraHelper对象;创建SurfaceTexture纹理对象,并绑定SurfaceTexture.OnFrameAvailableListener监听;创建ScreenFilter屏幕过滤器。

@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {Log.i(TAG, "onSurfaceCreated");mCameraHelper = new CameraHelper((Activity) myGLSurfaceView.getContext(), // 上下文Camera.CameraInfo.CAMERA_FACING_FRONT, // 前置摄像头640, 480);// 获取纹理ID【先理解成画布】mTextureID = new int[1];/*** 1.长度 只有一个 1* 2.纹理ID,是一个数组* 3.offset:0 使用数组的0下标*/glGenTextures(mTextureID.length, mTextureID, 0);mSurfaceTexture = new SurfaceTexture(mTextureID[0]); // 实例化纹理对象mSurfaceTexture.setOnFrameAvailableListener(this); // 绑定好此监听 SurfaceTexture.OnFrameAvailableListenermScreenFilter = new ScreenFilter(myGLSurfaceView.getContext());
}

2)当Surface改变时,回调onSurfaceChanged()函数,获得Camera对象,设置Camera绑定SurfaceTexture纹理对象,开启相机预览。

@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {Log.i(TAG, "onSurfaceChanged");mCameraHelper.startPreview(mSurfaceTexture); // 开始预览mScreenFilter.onReady(width, height);
}

实例化CameraHelper,打开Camera,设置Camera绑定SurfaceTexture纹理对象,开启相机预览。

public void startPreview(SurfaceTexture surfaceTexture) {mSurfaceTexture = surfaceTexture; // TODO 重点try {// 获得camera对象mCamera = Camera.open(mCameraID);// 配置camera的属性Camera.Parameters parameters = mCamera.getParameters();// 设置预览数据格式为nv21parameters.setPreviewFormat(ImageFormat.NV21);// 这是摄像头宽、高setPreviewSize(parameters);// 设置摄像头 图像传感器的角度、方向setPreviewOrientation(parameters);mCamera.setParameters(parameters);cameraBuffer = new byte[mWidth * mHeight * 3 / 2];  // 请看之前讲过的的细节cameraBuffer_ = new byte[mWidth * mHeight * 3 / 2]; // 请看之前讲过的的细节// 数据缓存区mCamera.addCallbackBuffer(cameraBuffer);mCamera.setPreviewCallbackWithBuffer(this);// 设置预览画面(之前的方式:把显示的画面,渲染到SurfaceView屏幕上即可)// mCamera.setPreviewDisplay(mSurfaceHolder); // SurfaceView 和 Camera绑定 ,以前音视频推流,就是这个干的// 设置预览画面(离屏渲染) surfaceTexture纹理画布(仅仅只是缓存一份画布,不可见的画布) 配合 OpenGL渲染操作// Camera相机预览数据 ---->  surfaceTexture纹理画布(不可见的画布) ---> OpenGL TODO 重点,绑定纹理mCamera.setPreviewTexture(surfaceTexture); // OpenGL无法直接访问到 Camera预览数据, 他只能访问 surfaceTexture// 开启预览mCamera.startPreview();} catch (Exception e) {e.printStackTrace();}
}

3)绘制一帧图像时,回调onDrawFrame()函数,获取纹理对象的图像数据,通过OpenGL渲染到屏幕;

@Override
public void onDrawFrame(GL10 gl) {Log.i(TAG, "onDrawFrame");// 每次清空之前的:例子:上课擦黑白 是一个道理glClearColor(255, 0, 0, 0); // 屏幕清理成颜色 红色,清理成红色的黑板一样// mask 细节看看此文章:https://blog.csdn.net/z136411501/article/details/83273874// GL_COLOR_BUFFER_BIT 颜色缓冲区// GL_DEPTH_BUFFER_BIT 深度缓冲区// GL_STENCIL_BUFFER_BIT 模型缓冲区glClear(GL_COLOR_BUFFER_BIT);// 绘制摄像头数据mSurfaceTexture.updateTexImage();  // 将纹理图像更新为图像流中最新的帧数据【刷新一下】// 画布,矩阵数据,通过Native层将数据存储到mtxmSurfaceTexture.getTransformMatrix(mtx);// 绘制一帧图像mScreenFilter.onDrawFrame(mTextureID[0], mtx);
}

2.实现SurfaceTexture.OnFrameAvailableListener接口,实现接口的onFrameAvailable()方法;

当有可用的数据时,回调onFrameAvailable()函数,手动调用,触发屏幕渲染

@Override
public void onFrameAvailable(SurfaceTexture surfaceTexture) {Log.i(TAG, "onFrameAvailable");myGLSurfaceView.requestRender(); // setRenderMode(RENDERMODE_WHEN_DIRTY); 配合用
}

四、ScreenFilter封装OpenGL

1.初始化ScreenFilter操作:

1)读取顶点着色器和片元着色器代码,转换为字符串

String vertexSource = readTextFileFromResource(context, R.raw.camera_vertex); 
String fragmentSource = readTextFileFromResource(context, R.raw.camera_fragment); 

2)配置顶点着色器

// 1.1 创建顶点着色器
int vShaderId = glCreateShader(GL_VERTEX_SHADER);
// 1.2 绑定着色器源代码到 着色器(加载着色器的代码)
glShaderSource(vShaderId, vertexSource);
// 1.3 编译着色器代码(编译阶段:编译成功就能拿到顶点着色器ID,编译失败基本上就是着色器代码字符串写错了)
glCompileShader(vShaderId);
// 1.4 获取着色器配置结果
int[] status = new int[1];
glGetShaderiv(vShaderId, GL_COMPILE_STATUS, status, 0);
if (status[0] != GL_TRUE) {throw new IllegalStateException("顶点着色器配置失败!");
}

3)配置片元着色器

// 2.1 创建片元着色器
int fShaderId = glCreateShader(GL_FRAGMENT_SHADER);
// 2.2 绑定着色器源代码到 着色器(加载着色器的代码)
glShaderSource(fShaderId, fragmentSource);
// 2.3 编译着色器代码(编译阶段:编译成功就能拿到顶点着色器ID,编译失败基本上就是着色器代码字符串写错了)
glCompileShader(fShaderId);
// 2.4 获取着色器配置结果
glGetShaderiv(fShaderId, GL_COMPILE_STATUS, status, 0);
if (status[0] != GL_TRUE) {throw new IllegalStateException("片元着色器配置失败!");
}

4)配置着色器程序

// 3.1 创建一个着色器程序
mProgram = glCreateProgram();
// 3.2 将前面配置的 顶点 和 片元 着色器 附加到新的程序 上
glAttachShader(mProgram, vShaderId); // 顶点
glAttachShader(mProgram, fShaderId); // 片元
// 3.3 链接着色器
glLinkProgram(mProgram); // mProgram着色器程序 是我们的成果
// 3.4 获取着色器配置结果
glGetShaderiv(mProgram, GL_LINK_STATUS, status, 0);
if (status[0] != GL_TRUE) {throw new IllegalStateException("着色器程序链接失败!");
}

5)获取顶点着色器和片元着色器代码的变量的索引值,通过索引来赋值

// 顶点着色器里面的如下:
vPosition = glGetAttribLocation(mProgram, "vPosition"); // 顶点着色器:的索引值
vCoord = glGetAttribLocation(mProgram, "vCoord"); // 顶点着色器:纹理坐标,采样器采样图片的坐标 的索引值
vMatrix = glGetUniformLocation(mProgram, "vMatrix"); // 顶点着色器:变换矩阵 的索引值// 片元着色器里面的如下:
vTexture = glGetUniformLocation(mProgram, "vTexture"); // 片元着色器:采样器

6)缓存顶点坐标(顶点:位置 排版)

mVertexBuffer = ByteBuffer.allocateDirect(4 * 2 * 4) // 分配内存 坐标个数 * xy坐标数据类型 * float占几字节.order(ByteOrder.nativeOrder()) // 使用本地字节序,例如:大端模式,小端模式,这里设置为:跟随OpenGL的变化二变化.asFloatBuffer();
mVertexBuffer.clear(); // 清除一下
float[] v = { // OpenGL世界坐标-1.0f, -1.0f,1.0f, -1.0f,-1.0f, 1.0f,1.0f, 1.0f,
};
mVertexBuffer.put(v);

7)缓存纹理坐标(纹理:上色 成果)

mTexturBuffer = ByteBuffer.allocateDirect(4 * 2 * 4) // 分配内存 坐标个数 * xy坐标数据类型 * float占几字节.order(ByteOrder.nativeOrder()) // 使用本地字节序,例如:大端模式,小端模式,这里设置为:跟随OpenGL的变化二变化.asFloatBuffer();
mTexturBuffer.clear(); // 清除一下
// 旋转 180度 就纠正了
float[] t = { // 屏幕坐标系1.0f, 0.0f,0.0f, 0.0f,1.0f, 1.0f,0.0f, 1.0f,
};
mTexturBuffer.put(t);

2.绘制操作

通过OpenGL顶点着色器,规划位置;设置顶点坐标相当于,相机的四个点位置排版;设置纹理坐标,用来图形上色;设置图形矩阵数据;

通过OpenGL片元着色器,给图片上色;设置采样器,获取顶点着色器设置的纹理坐标和矩阵数据的最终计算成果,通知OpenGL绘制。

1)顶点着色器

// TODO 1.1 顶点坐标赋值  NIO的Buffer 用它就要归零,习惯
mVertexBuffer.position(0); // 养成好习惯,每次来用他时,归零(为了从坐标位置的起始开始)
/*** 传值(把float[]值传递给顶点着色器)把mVertexBuffer传递到vPosition == size:每次两个xy, stride:0 不跳步* 1.着色器代码里面的 标记变量 attribute vec4 vPosition;* 2.xy 所以是两个* 3.不用管* 4.不用管* 5.跳步 0 不跳步* 6.顶点坐标nio的buffer缓存数据*/
glVertexAttribPointer(vPosition, 2, GL_FLOAT, false, 0, mVertexBuffer);
// 激活
glEnableVertexAttribArray(vPosition);// TODO 1.2 纹理坐标赋值
mTexturBuffer.position(0); // 养成好习惯,每次来用他时,归零(为了从坐标位置的起始开始)
// 传值(把float[]值传递给纹理)把mTexturBuffer传递到vCoord == size:每次两个xy, stride:不跳步
glVertexAttribPointer(vCoord, 2, GL_FLOAT, false, 0, mTexturBuffer);
// 激活
glEnableVertexAttribArray(vCoord);// TODO 1.3 变换矩阵 把mtx矩阵数据 传递到 vMatrix
glUniformMatrix4fv(vMatrix, 1, false, mtx, 0);

2)片元着色器

// 激活图层
glActiveTexture(GL_TEXTURE0);
// TODO 2.1 绑定纹理ID --- glBindTexture(GL_TEXTURE_2D ,textureId); 如果在片元着色器中的vTexture,不是samplerExternalOES类型,就可以这样写
glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, mTextureID); // 由于我们的着色器代码是 使用了 samplerExternalOES
// TODO 2.2 采样器赋值
glUniform1i(vTexture, 0); // 传递参数 给 片元着色器:采样器
// TODO 2.3 通知 opengl 绘制 ,从0开始,共四个点绘制
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

五、着色器代码工作

1)顶点着色器

attribute vec4 vPosition; // 顶点坐标,相当于:相机的四个点位置排版attribute vec4 vCoord; // 纹理坐标,用来图形上色的uniform mat4 vMatrix; // 变换矩阵,4*4的格式的varying vec2 aCoord; // 把这个最终的计算成果,给片元着色器 【不需要Java传递,他是计算出来的】void main() {gl_Position = vPosition; // 确定好位置排版aCoord = (vMatrix * vCoord).xy; // 兼容所有设备
}

2)片元着色器

// 导入 samplerExternalOES 的意思
#extension GL_OES_EGL_image_external : require// float 数据的精度 (precision lowp = 低精度) (precision mediump = 中精度) (precision highp = 高精度)
precision mediump float;// 根据上面的数据的精度,写下面的 采样器 相机的数据
// uniform sampler2D vTexture;  由于我们用的是 安卓的相机,就不能用他
uniform samplerExternalOES vTexture; // samplerExternalOES才能采样相机的数据varying vec2 aCoord; // 把这个最终的计算成果,给片元着色器,拿到最终的成果,我才能上色void main() {// texture2D (采样器, 坐标) 正常效果// gl_FragColor = texture2D(vTexture, aCoord);// 305911公式:黑白电视效果,其实原理就是提取出Y分量/*vec4 rgba =texture2D(vTexture, aCoord);float gray = (0.30 * rgba.r   + 0.59 * rgba.g + 0.11* rgba.b); // 其实原理就是提取出Y分量 ,就是黑白电视gl_FragColor = vec4(gray, gray, gray, 1.0);*/// 底片效果vec4 rgba = texture2D(vTexture,aCoord);  // rgbagl_FragColor = vec4(1.-rgba.r, 1.-rgba.g, 1.-rgba.b, rgba.a);
}

至此,OpenGL渲染画面效果技术实战项目已完成;黑白电视和大眼萌等特效都可以通过OpenGL实现。

源码:

NdkOpenGLPlay: NDK OpenGL渲染画面效果

相关文章:

NDK OpenGL渲染画面效果

NDK系列之OpenGL渲染画面效果技术实战,本节主要是通过OpenGL Java库(谷歌对OpenGL C库做了JIN封装,核心实现还是在Native层),实现页面渲染,自定义渲染特效。 实现效果: 实现逻辑: 1…...

常见的深度学习框架

框架优点缺点TensorFlow- 由Google开发和维护,社区庞大,学习资源丰富- 具备优秀的性能表现,支持大规模分布式计算- 支持多种编程语言接口,易于使用- 提供了可视化工具TensorBoard,可用于调试和可视化模型- 底层架构复杂…...

【设计模式】七大设计原则--------单一职责原则

文章目录 1.案例1.1 原始案例1.2 改进一:类上遵循单一职责原则1.3 改进二:方法上遵循单一职责原则 2.小结 1.案例 1.1 原始案例 package com.sdnu.principle.singleresponsibility; //客户端 public class singleResponsibility {public static void m…...

MySQL-中间件mycat(一)

目录 🍁mycat基础概念 🍁Mycat安装部署 🍃初始环境 🍃测试环境 🍃下载安装 🍃修改配置文件 🍃启动mycat 🍃测试连接 🦐博客主页:大虾好吃吗的博客 &#x1f9…...

ARM寄存器组织

ARM有37个32位长的寄存器: 1个用做PC(Program Counter); 1个用做CPSR(Current Program Status Register); 5个用做SPSR(Saved Program Status Registers); 30个通用寄存器。 AR…...

记录一次webdav协议磁盘挂载经验总结

记录一次磁盘挂载经验总结 文章目录 记录一次磁盘挂载经验总结适配环境服务器协议适配方案脚本与详细说明 适配环境 windows 11windows 10windows 7 x86 and x64linuxuos统信国产化linux系统 服务器协议 webdav 适配方案 一、通用 winfsprclone 已验证通过,版…...

安装Django

1. 在物理环境安装Django Python官方的PyPi仓库为我们提供了一个统一的代码托管仓库,所有的第三方库,甚至你自己写的开源模块,都可以发布到这里,让全世界的人分享下载 pip是最有名的Python包管理工具 。提供了对Python包的查找、…...

【前端面经】JS-如何使用 JavaScript 来判断用户设备类型?

在 Web 开发中,有时需要针对不同的设备类型进行不同的处理。例如,对于移动设备,我们可能需要采用不同的布局或者交互方式,以提供更好的用户体验。因此,如何判断用户设备类型成为了一个重要的问题。 1. 使用 navigator…...

压缩HTML引用字体

内容简介 有些网站为了凸显某部分字体,而引入自定义字体,但由于自定义字体相对都比较大(几M),导致页面加载缓慢;所以本文介绍三种压缩字体的方法,可根据项目情况自行选择。 压缩方法 1、利用Fontmin程序&a…...

大厂高频面试:底层的源码逻辑知多少?

你好,我是何辉。今天我们来聊一聊Dubbo的大厂高频面试题。 大厂面试,一般重点考察对技术理解的深度,和中小厂的区别在于,不仅要你精于实战,还要你深懂原理,勤于思考并针对功能进行合理的设计。 网上一直流…...

【学习笔记】CF607E Cross Sum

最后一道数据结构,不能再多了。 而且需要一点计算几何的知识,有点难搞。 分为两个部分求解。 首先考虑找到距离 ≤ r \le r ≤r的交点数量。发现这等价于圆上两段圆弧相交,因此将圆上的点离散化后排序,用一个主席树来求就做完了…...

Python 一元线性回归模型预测实验完整版

一元线性回归预测模型 实验目的 通过一元线性回归预测模型,掌握预测模型的建立和应用方法,了解线性回归模型的基本原理 实验内容 一元线性回归预测模型 实验步骤和过程 (1)第一步:学习一元线性回归预测模型相关知识。 线性回归模型属于…...

GStreamer第一阶段的简单总结

这里写目录标题 前言个人的总结v4l2src插件的简单使用 前言 因为涉及很多细节的GStreamer官方论坛有详细解链接: GStreamer官网,这里不做说明,以下只是涉及到个人的理解和认知,方便后续的查阅。 个人的总结 1)了解pipeline的使用&#xff0…...

【网络进阶】服务器模型Reactor与Proactor

文章目录 1. Reactor模型2. Proactor模型3. 同步IO模拟Proactor模型 在高并发编程和网络连接的消息处理中,通常可分为两个阶段:等待消息就绪和消息处理。当使用默认的阻塞套接字时(例如每个线程专门处理一个连接),这两…...

使用div替代<frameset><frame>的问题以及解决办法

首先是原版三层框架的html&#xff1a; <html> <head> <title>THPWP</title> </head> <!-- 切记frameset不能写在body里面&#xff0c;以下代表首页由三层模块组成&#xff0c;其中第一层我是用来放菜单高度占比14%&#xff0c;中间的用作主…...

Verilog中的`define与`if的使用

一部分代码可能有时候用&#xff0c;有时候不用&#xff0c;为了避免全部编译占用资源&#xff0c;可以使用条件编译语句。 语法 // Style #1: Only single ifdef ifdef <FLAG>// Statements endif// Style #2: ifdef with else part ifdef <FLAG>// Statements …...

沃尔玛、亚马逊影响listing的转化率4大因素,测评补单自养号解析

1、listing的相关性&#xff1a;前期我们在找词&#xff0c;收集词的时候&#xff0c;我们通过插件来协助我们去筛选词。我们把流量高&#xff0c;中&#xff0c;低的关键词都一一收集&#xff0c;然后我们再进行对收集得来的关键词进行分析&#xff0c;再进行挑词&#xff0c;…...

静态分析和动态分析

在开发早期&#xff0c;发现并修复bug在许多方面都有好处。它可以减少开发时间&#xff0c;降低成本&#xff0c;并且防止数据泄露或其他安全漏洞。特别是对于DevOps&#xff0c;尽早持续地将测试纳入SDLC软件开发生命周期是非常有帮助的。 这就是动态和静态分析测试的用武之地…...

代码随想录_贪心_leetcode 1005 134

leetcode 1005. K 次取反后最大化的数组和 1005. K 次取反后最大化的数组和 给你一个整数数组 nums 和一个整数 k &#xff0c;按以下方法修改该数组&#xff1a; 选择某个下标 i 并将 nums[i] 替换为 -nums[i] 。 重复这个过程恰好 k 次。可以多次选择同一个下标 i 。 以…...

笔记:对多维torch进行任意维度的多“行”操作

如何取出多维torch指定维度的指定“行” 从二维torch开始新建torch取出某一行取出某一列一次性取出多行取出连续的多行取出不连续的多行 一次取出多列取出连续的多列取出不连续的多列 考虑三维torch取出三维torch的任意两行&#xff08;means 在dim0上操作&#xff09;取出连续…...

【VSCode】1、VSCode 如何连接服务器

文章目录 一、安装 remote-ssh 插件二、直接连接三、配置 SSH 公匙&#xff0c;免密登录 一、安装 remote-ssh 插件 点击插件搜索框&#xff0c;搜 remote-ssh&#xff0c;点击安装 安装完成后就会出现下面的图标&#xff1a; 二、直接连接 点击加号&#xff0c;输入 ssh 连接…...

AI工具:通过智能实现工作和学习效率的革命化

AI工具是指一系列人工智能技术和工具&#xff0c;包括机器学习、深度学习、自然语言处理、计算机视觉等。这些工具可以帮助开发人员和数据科学家通过处理和分析海量数据来自动识别和解决问题&#xff0c;提供智能的决策和预测模型。常见的AI工具包括TensorFlow、PyTorch、Keras…...

static 和构造方法

文章目录 static构造方法内存中数据的存储方式示例 static 具体对象的属性&#xff0c;称之为对象属性&#xff0c;成员属性&#xff0c;实例属性。 具体对象的方法&#xff0c;称之为对象方法&#xff0c;成员方法&#xff0c;实例方法。 静态&#xff1a;static 和具体对…...

【Linux 裸机篇(八)】I.MX6U EPIT 定时器中断、定时器按键消抖

目录 一、EPIT 定时器简介二、定时器按键消抖 一、EPIT 定时器简介 EPIT 的全称是&#xff1a; Enhanced Periodic Interrupt Timer&#xff0c;直译过来就是增强的周期中断定时器&#xff0c;它主要是完成周期性中断定时的。学过 STM32 的话应该知道&#xff0c; STM32 里面的…...

Web安全 XSS靶场搭建(玩转整个XSS环境.)

Web安全 XSS靶场搭建 XSS又叫CSS&#xff08;Cross Site Script&#xff09;跨站脚本攻击&#xff0c;指的是攻击者在Web页面&#xff0c;插入恶意JS代码&#xff0c;当用户浏览该页之时&#xff0c;嵌入其中JS代码就会被执行&#xff0c;从而达到攻击的目的.&#xff08;包含…...

前端开发技术——DOM(上)

一.单选题&#xff08;共4题,44.4分&#xff09; 1 下列选项中&#xff0c;关于事件的描述错误的是&#xff08;&#xff09; A、 事件指的是可以被JavaScript侦测到的行为 B、 事件驱动程序指的是事件触发后要执行的代码 C、 事件源是指触发的事件 D、 事件的种类称为事件…...

银河麒麟v10服务器版安装OpenDDS

1. OpenDDS简介 OpenDDS是OMG数据分发服务(DDS)的一种开源实现&#xff0c;它遵循实时系统v1.2的DDS规范(OMG Document formal/07-01-01)和实时公布/订阅互操作性通信协议v2.1的DDS-RTPS规范(OMG Document formal/2010-11-01)。OpenDDS由OCI公司设计和维护&#xff0c;可从http…...

curl方式调用电商API接口示例 详细介绍

cURL是一个利用URL语法在命令行下工作的文件传输工具&#xff0c;1997年首次发行。它支持文件上传和下载&#xff0c;所以是综合传输工具&#xff0c;但按传统&#xff0c;习惯称cURL为下载工具。cURL还包含了用于程序开发的libcurl。 cURL支持的通信协议有FTP、FTPS、HTTP、H…...

Duboo介绍与入门

文章目录 1、Dubbo的前世今生2、Dubbo的快速入门2.1、Dubbo的基本架构2.2、Nacos2.3、管理后台2.4、入门案例2.4.1、服务提供者搭建环境代码实现配置文件 2.4.2、服务消费者搭建环境代码实现配置文件 最后说一句 1、Dubbo的前世今生 2011年10月27日&#xff0c;阿里巴巴开源了…...

人工智能中(Pytorch)框架下模型训练效果的提升方法

大家好&#xff0c;我是微学AI&#xff0c;今天给大家介绍一下人工智能中(Pytorch)框架下模型训练效果的提升方法。随着深度学习技术的快速发展&#xff0c;越来越多的应用场景需要建立复杂的、高精度的深度学习模型。为了实现这些目标&#xff0c;必须采用一系列复杂的技术来提…...