融媒体服务中PBO进行多重采样抗锯齿(MSAA)

如果不理解pbo 那先去了解概念,在此不再解释,这是我为了做融合服务器viewpointserver做的一部分工作,融合服务器的功能是将三维和流媒体,AI融合在一起,viewpointserver会直接读取三维工程的文件,同时融合rtsp视频流,将视频流作为纹理给材质,最后赋值给三维模型如fbx的表面。由于没有窗口,三维作为服务运行,里面有一项工作就是三维的抗锯齿采集。

PBO(Pixel Buffer Object)进行多重采样抗锯齿(MSAA)的一般步骤

1 初始化 OpenGL 和 MSAA 帧缓冲:

1.1开启 MSAA:

在初始化 OpenGL 时,通过设置相关参数开启多重采样抗锯齿。例如,使用 glEnable(GL_MULTISAMPLE) 函数来启用 OpenGL 的多重采样功能。

1.2 创建帧缓冲:

创建一个帧缓冲对象(FBO),用于存储多重采样后的图像数据。这可以通过 glGenFramebuffers 和 glBindFramebuffer 等函数来完成。

1.3 配置 FBO 的附件:

为 FBO 配置颜色附件和深度附件。对于颜色附件,创建一个纹理,并将其绑定到 FBO 上;对于深度附件,可以创建一个渲染缓冲对象(RBO)并绑定到 FBO。确保纹理和 RBO 的尺寸与渲染窗口的尺寸相匹配。

2 渲染到 MSAA 帧缓冲:

2.1 绑定 MSAA 帧缓冲:

在渲染场景之前,使用 glBindFramebuffer 函数将之前创建的 MSAA FBO 绑定为当前的渲染目标。这样,后续的渲染操作将把图像数据渲染到 MSAA FBO 中。

2.2 进行常规渲染:

按照正常的 OpenGL 渲染流程绘制场景中的物体。由于启用了 MSAA,OpenGL 会在每个像素内进行多个子采样,以实现抗锯齿效果。

3 使用 PBO 读取 MSAA 数据:

创建 PBO:使用 glGenBuffers 函数创建一个 PBO,并使用 glBindBuffer 函数将其绑定到 GL_PIXEL_PACK_BUFFER 目标上。然后,使用 glBufferData 函数为 PBO 分配足够的内存空间,以存储从 MSAA FBO 读取的像素数据。
读取像素数据到 PBO:在渲染完成后,使用 glReadPixels 函数将 MSAA FBO 中的像素数据读取到 PBO 中。由于 PBO 的存在,这个操作可以在后台异步进行,减少对 CPU 的阻塞。

4 处理和解析 PBO 中的数据:

4.1 映射 PBO:

使用 glMapBuffer 函数将 PBO 映射到 CPU 可访问的内存空间,以便读取和处理像素数据。这将返回一个指向 PBO 内存的指针,可以通过该指针访问像素数据。

4.2 解析像素数据:

根据需要,对 PBO 中的像素数据进行处理和解析。例如,可以将像素数据转换为图像格式,以便保存为文件或进行其他操作。在处理像素数据时,需要考虑 MSAA 的子采样信息,通常需要对多个子采样点的颜色值进行合并或平均,以得到最终的抗锯齿效果。

4.3 取消映射 PBO:

完成对 PBO 数据的处理后,使用 glUnmapBuffer 函数取消对 PBO 的映射,释放 CPU 对 PBO 内存的访问。

5 显示或使用抗锯齿后的图像:

5.1 将处理后的像素数据显示在屏幕上:

如果需要在屏幕上显示抗锯齿后的图像,可以使用 glDrawPixels 或其他相关的 OpenGL 函数将处理后的像素数据绘制到默认的帧缓冲中,然后通过交换缓冲区来显示在屏幕上。

5.2 保存为图像文件:

可以将处理后的像素数据保存为图像文件,以便后续使用。这可以通过使用图像库(如 stb_image 库)来实现,将像素数据写入图像文件中。

使用深度缓冲的例子

以下使用qt来做,qt的优点是很多都是封装好的,比较容易实现,不用引入额外的库,当然我们也可以使用glfw来做,后面会给出例子

#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QtWidgets/QWidget>
#include <QOpenGLWidget>
#include <QOpenGLFunctions_4_5_Core>
#include <QOpenGLVertexArrayObject>
#include <QOpenGLBuffer>
#include <QOpenGLTexture>
#include <QOpenGLShader>
#include <QOpenGLShaderProgram>
#include "ui_MainWindow.h"QT_BEGIN_NAMESPACE
namespace Ui {class CMainWindow;
}
QT_END_NAMESPACEclass CMainWindow : public QOpenGLWidget, protected QOpenGLFunctions_4_5_Core
{Q_OBJECTpublic:CMainWindow(QWidget *parent = Q_NULLPTR);~CMainWindow();void initFBO();protected:void initializeGL();void paintGL();void resizeGL(int w, int h);private:QImage m_img;GLsizei m_width = 0;GLsizei m_height = 0;GLsizeiptr m_dataSize = 0;GLuint m_VBO = 0;GLuint m_VAO = 0;GLuint m_EBO = 0;GLuint m_texture = 0;GLuint m_frameBuffer = 0;GLuint m_RBO = 0;GLuint m_fVBO = 0;GLuint m_fVAO = 0;GLuint m_textureFBO = 0;QOpenGLShaderProgram *m_programScreen = nullptr;QOpenGLShaderProgram *m_shaderProgram = nullptr;
private:Ui::CMainWindow *ui;
};
#endif //MAINWINDOW_H
#include "MainWindow.h"CMainWindow::CMainWindow(QWidget* parent): QOpenGLWidget(parent), ui(new Ui::CMainWindow)
{ui->setupUi(this);m_img = QImage("2.jpg");//picturem_width = m_img.width();m_height = m_img.height();m_dataSize = m_width * m_height * 3;
}CMainWindow::~CMainWindow()
{delete ui;glDeleteVertexArrays(1, &m_VAO);glDeleteBuffers(1, &m_VBO);glDeleteBuffers(1, &m_EBO);glDeleteVertexArrays(1, &m_fVAO);glDeleteBuffers(1, &m_fVBO);glDeleteBuffers(1, &m_frameBuffer);glDeleteBuffers(1, &m_RBO);
}
void CMainWindow::initFBO()
{glGenFramebuffers(1, &m_frameBuffer);glBindFramebuffer(GL_FRAMEBUFFER, m_frameBuffer);glGenTextures(1, &m_textureFBO);glBindTexture(GL_TEXTURE_2D, m_textureFBO);glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, m_width, m_height, 0, GL_BGRA, GL_UNSIGNED_BYTE, nullptr);//TODOglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);glBindTexture(GL_TEXTURE_2D, 0);glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_textureFBO, 0);glGenRenderbuffers(1, &m_RBO);glBindRenderbuffer(GL_RENDERBUFFER, m_RBO);glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, m_width, m_height);glBindRenderbuffer(GL_RENDERBUFFER, 0);glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, m_RBO);if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)qDebug() << "ERROR::FRAMEBUFFER:: Framebuffer is not complete!" ;glBindFramebuffer(GL_FRAMEBUFFER, 0);char vertexShaderSource[] ="#version 450 core\n""layout (location = 0) in vec2 aPos;\n""layout (location = 1) in vec2 aTexCoords;\n""out vec2 TexCoords;\n""void main()\n""{\n""   gl_Position = vec4(aPos.x, aPos.y, 0.0, 1.0);\n""TexCoords = aTexCoords;\n""}\n";char fragmentShaderSource[] ="#version 450 core\n""out vec4 FragColor;\n""in vec2 TexCoords;\n""uniform sampler2D screenTexture;\n""void main()\n""{\n""   FragColor = texture(screenTexture, TexCoords);\n""}\n";m_programScreen = new QOpenGLShaderProgram;m_programScreen->addShaderFromSourceCode(QOpenGLShader::Vertex, vertexShaderSource);m_programScreen->addShaderFromSourceCode(QOpenGLShader::Fragment, fragmentShaderSource);m_programScreen->link();m_programScreen->bind();m_programScreen->setUniformValue("screenTexture", 1);m_programScreen->release();float fb_Vertices[] = {// positions   // texCoords-1.0f,  1.0f,  0.0f, 1.0f,-1.0f, -1.0f,  0.0f, 0.0f,1.0f, -1.0f,  1.0f, 0.0f,-1.0f,  1.0f,  0.0f, 1.0f,1.0f, -1.0f,  1.0f, 0.0f,1.0f,  1.0f,  1.0f, 1.0f};glGenVertexArrays(1, &m_fVAO);glBindVertexArray(m_fVAO);glGenBuffers(1, &m_fVBO);glBindBuffer(GL_ARRAY_BUFFER, m_fVBO);glBufferData(GL_ARRAY_BUFFER, sizeof(fb_Vertices), fb_Vertices, GL_STATIC_DRAW);glEnableVertexAttribArray(0);glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), (void*)0);glEnableVertexAttribArray(1);glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), (void*)(2 * sizeof(float)));glBindBuffer(GL_ARRAY_BUFFER, 0);glBindVertexArray(0);}void CMainWindow::initializeGL()
{this->initializeOpenGLFunctions();char vertexShaderSource[] ="#version 450 core\n""layout(location = 0) in vec3 aPos;\n""layout(location = 1) in vec3 aColor;\n""layout(location = 2) in vec2 aTexcood;\n""out vec3 vertexColor;\n""out vec2 m_tex;\n""void main()\n""{\n""   m_tex = aTexcood;\n""   vertexColor = aColor;\n""   gl_Position = vec4(aPos, 1.0);\n""}\n";char fragmentShaderSource[] ="#version 450 core\n""out vec4 FragColor;\n""in vec3 vertexColor;\n""in vec2 m_tex;\n""uniform sampler2D ourTexture;\n""void main()\n""{\n""   FragColor = texture2D(ourTexture, m_tex) * vec4(vertexColor, 1.0f);\n""}\n";m_shaderProgram = new QOpenGLShaderProgram;m_shaderProgram->addShaderFromSourceCode(QOpenGLShader::Vertex, vertexShaderSource);m_shaderProgram->addShaderFromSourceCode(QOpenGLShader::Fragment, fragmentShaderSource);m_shaderProgram->link();m_shaderProgram->bind();m_shaderProgram->setUniformValue("ourTexture", 0);m_shaderProgram->release();GLfloat vertices[] = {-1.0f, -1.0f,0.0f, 0.0f,0.0f,1.0f, 0.0f,0.0f,1.0f, -1.0f,0.0f, 0.0f,1.0f,0.0f, 1.0f,0.0f,1.0f,  1.0f,0.0f, 1.0f,0.0f,0.0f, 1.0f,1.0f,-1.0f,  1.0f,0.0f, 0.0f,1.0f,1.0f, 0.0f,1.0f,};GLuint indices[] = {0,1,2,0,2,3};glGenVertexArrays(1, &m_VAO);glBindVertexArray(m_VAO);glGenBuffers(1, &m_VBO);glBindBuffer(GL_ARRAY_BUFFER, m_VBO);glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);glGenBuffers(1, &m_EBO);glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_EBO);glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (void*)0);glEnableVertexAttribArray(0);glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (void*)(3 * sizeof(float)));glEnableVertexAttribArray(1);glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (void*)(6 * sizeof(float)));glEnableVertexAttribArray(2);glBindVertexArray(0);glBindBuffer(GL_ARRAY_BUFFER, 0);glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);glGenTextures(1, &m_texture);glBindTexture(GL_TEXTURE_2D, m_texture);glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, m_width, m_height, 0, GL_BGRA, GL_UNSIGNED_BYTE, m_img.bits());//TODOglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);glGenerateMipmap(GL_TEXTURE_2D);glBindTexture(GL_TEXTURE_2D, 0);//初始化FBOinitFBO();}void CMainWindow::paintGL()
{glBindFramebuffer(GL_FRAMEBUFFER, m_frameBuffer);glEnable(GL_DEPTH_TEST);glClearColor(0.5f, 0.0f, 0.0f, 1.0f);glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);m_shaderProgram->bind();glBindVertexArray(m_VAO);glActiveTexture(GL_TEXTURE0);glBindTexture(GL_TEXTURE_2D, m_texture);glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, NULL);glBindVertexArray(0);glBindTexture(GL_TEXTURE_2D, 0);m_shaderProgram->release();/********** 关键之处 ***********/GLuint fb = context()->defaultFramebufferObject();glBindFramebuffer(GL_FRAMEBUFFER, fb);glDisable(GL_DEPTH_TEST);glClearColor(1.0f, 1.0f, 1.0f, 1.0f);glClear(GL_COLOR_BUFFER_BIT);glViewport(0, 0, m_width, m_height);m_programScreen->bind();glBindVertexArray(m_fVAO);glActiveTexture(GL_TEXTURE1);glBindTexture(GL_TEXTURE_2D, m_textureFBO);glDrawArrays(GL_TRIANGLES, 0, 6);glBindVertexArray(0);glBindTexture(GL_TEXTURE_2D, 0);m_programScreen->release();}void CMainWindow::resizeGL(int w, int h)
{glViewport(0, 0, w, h);
}

qt中采集场景如图
在这里插入图片描述

下面给出glfw的例子

glfw

首先初始化 OpenGL、GLFW 和 GLEW,也可以用glad,并创建了 MSAA FBO、颜色纹理、深度 RBO 和 PBO。然后,在渲染循环中,先将场景渲染到 MSAA FBO 中,再将 FBO 中的像素数据读取到 PBO 中,并对 PBO 中的像素数据进行处理。最后,清理资源并退出程序。当然实际应用中确实需要根据具体需求进行更多的错误处理和优化。

#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <iostream>
#include <cstdlib>// 窗口尺寸
const int WIDTH = 800;
const int HEIGHT = 600;// 创建 PBO
GLuint pbo;
// 创建 MSAA FBO
GLuint fbo;
// 颜色纹理
GLuint colorTexture;
// 深度 RBO
GLuint depthRBO;void init() {// 初始化 GLFWif (!glfwInit()) {std::cerr << "Failed to initialize GLFW" << std::endl;exit(EXIT_FAILURE);}// 创建窗口GLFWwindow* window = glfwCreateWindow(WIDTH, HEIGHT, "MSAA with PBO", nullptr, nullptr);if (!window) {std::cerr << "Failed to create GLFW window" << std::endl;glfwTerminate();exit(EXIT_FAILURE);}// 将窗口设置为当前上下文glfwMakeContextCurrent(window);// 初始化 GLEWglewExperimental = GL_TRUE;if (glewInit()!= GLEW_OK) {std::cerr << "Failed to initialize GLEW" << std::endl;exit(EXIT_FAILURE);}// 开启多重采样抗锯齿glEnable(GL_MULTISAMPLE);// 创建 FBOglGenFramebuffers(1, &fbo);glBindFramebuffer(GL_FRAMEBUFFER, fbo);// 创建颜色纹理glGenTextures(1, &colorTexture);glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, colorTexture);glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 4, GL_RGBA8, WIDTH, HEIGHT, GL_TRUE);glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, colorTexture, 0);// 创建深度 RBOglGenRenderbuffers(1, &depthRBO);glBindRenderbuffer(GL_RENDERBUFFER, depthRBO);glRenderbufferStorageMultisample(GL_RENDERBUFFER, 4, GL_DEPTH24_STENCIL8, WIDTH, HEIGHT);glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, depthRBO);// 检查 FBO 是否完整if (glCheckFramebufferStatus(GL_FRAMEBUFFER)!= GL_FRAMEBUFFER_COMPLETE) {std::cerr << "Failed to create FBO" << std::endl;exit(EXIT_FAILURE);}// 创建 PBOglGenBuffers(1, &pbo);glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo);glBufferData(GL_PIXEL_PACK_BUFFER, WIDTH * HEIGHT * 4, nullptr, GL_STREAM_READ);
}void renderScene() {// 绑定 MSAA FBO 并渲染场景glBindFramebuffer(GL_FRAMEBUFFER, fbo);glViewport(0, 0, WIDTH, HEIGHT);glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);// 在这里进行场景的绘制操作// 解除绑定 FBOglBindFramebuffer(GL_FRAMEBUFFER, 0);
}void processPixels() {// 将 MSAA FBO 中的像素数据读取到 PBOglBindBuffer(GL_PIXEL_PACK_BUFFER, pbo);glReadPixels(0, 0, WIDTH, HEIGHT, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);// 映射 PBO 到 CPU 可访问的内存GLubyte* pixels = (GLubyte*)glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY);if (pixels) {// 在这里处理像素数据,例如保存为图像或进行其他操作// 为了简单起见,这里只是打印一些像素信息for (int i = 0; i < 10; i++) {std::cout << "Pixel " << i << ": ("<< (int)pixels[4 * i] << ", "<< (int)pixels[4 * i + 1] << ", "<< (int)pixels[4 * i + 2] << ", "<< (int)pixels[4 * i + 3] << ")" << std::endl;}// 取消映射 PBOglUnmapBuffer(GL_PIXEL_PACK_BUFFER);}
}int main() {init();// 渲染循环while (!glfwWindowShouldClose(glfwGetCurrentContext())) {renderScene();processPixels();// 交换缓冲区并处理事件glfwSwapBuffers(glfwGetCurrentContext());glfwPollEvents();}// 清理资源glDeleteBuffers(1, &pbo);glDeleteTextures(1, &colorTexture);glDeleteRenderbuffers(1, &depthRBO);glDeleteFramebuffers(1, &fbo);glfwTerminate();return 0;
}

存文件测试

static void saveImage(GLuint& pbo, const std::string& filename, int width, int height) {glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo);// 将帧缓冲区内容读取到 PBOglReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);// 映射 PBO 获取数据指针GLubyte* pixels = (GLubyte*)glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY);if (pixels){stbi_write_png(filename.c_str(), width, height, 4, pixels, width * 4);glUnmapBuffer(GL_PIXEL_PACK_BUFFER);}else{std::cerr << "Failed to map." << std::endl;}glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
}

如下图所示,存的图像是倒立镜像的,实际上是正立的三角形,还没有将视频附上去,工作量有些大,等到下一个文章再写。
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/1554702.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

BUCK的工作模式:CCM BCM DCM

连续导通模式CCM CCM工作状态 一个开关周期内&#xff0c;电感内的电流始终大于0&#xff0c;电感在DCDC整个工作周期中一直处于充电放电状态&#xff1b;即使DCDC的功率开关管断开时&#xff08;Toff&#xff09;&#xff0c;电感中一直有电流流过&#xff1b; 功率开关管闭合…

分布式学习02-CAP理论

文章目录 CAP三指标一致性可用性分区容错性 CAP不可能三角P存在的必要性CP理论AP理论 CAP理论对分布式系统的特性做了高度抽象&#xff0c;将其抽象为一致性、可用性、分区容错性。 并对特征间的冲突做了总结&#xff1a;CAP不可能三角。 CAP三指标 一致性&#xff08;Consis…

PostgreSQL Docker Error – 5432: 地址已被占用

PostgreSQL Docker Error – 5432: 地址已被占用 今天在学习【Spring Boot React】价值79.9美元&#xff0c;全栈开发&#xff0c;搭建个人网站、做毕业设计、试试这套课程第17~21节视频的时候&#xff0c;发现运行docker run --name demo-postgres -e POSTGRES_PASSWORDpass…

循环生成对抗网络——CycleGAN

系列文章目录 GAN生成对抗网络介绍 目录 系列文章目录 前言 二、应用 三、解决的问题 1、图像转译任务 2、原理 四、调试好的源码 前言 CycleGAN&#xff08;循环生成对抗网络&#xff09;是一种用于图像到图像的转换的深度学习模型&#xff0c;由Jun-Yan Zhu等人在20…

Redis数据库与GO(一):安装,string,hash

安装包地址&#xff1a;https://github.com/tporadowski/redis/releases 建议下载zip版本&#xff0c;解压即可使用。解压后&#xff0c;依次打开目录下的redis-server.exe和redis-cli.exe&#xff0c;redis-cli.exe用于输入指令。 一、基本结构 如图&#xff0c;redis对外有个…

【ubuntu】ubuntu20.04安装chrome浏览器

1.下载 https://download.csdn.net/download/qq_35975447/89842972 https://www.google.cn/chrome/ 2.安装 sudo dpkg -i google-chrome-stable_current_amd64.deb 3.使用

【AI学习】Mamba学习(一):总体架构

论文&#xff1a;《Mamba: Linear-Time Sequence Modeling with Selective State Spaces》 作者1&#xff1a;Albert Gu&#xff0c;现在是CMU(卡内基梅隆大学)助理教授&#xff0c;曾在DeepMind 工作。多年来一直推动SSM架构发展。 作者2&#xff1a;Tri Dao&#xff0c;现为…

文件上传之%00截断(00截断)以及pikachu靶场

pikachu的文件上传和upload-lab的文件上传 目录 mime type类型 getimagesize 第12关%00截断&#xff0c; 第13关0x00截断 差不多了&#xff0c;今天先学文件上传白名单&#xff0c;在网上看了资料&#xff0c;差不多看懂了&#xff0c;但是还有几个地方需要实验一下&#…

老年人意外跌倒感知技术

意外跌倒是导致老年人仙游的6大原因之一&#xff0c;尤其多余80岁以上的老年人。跌倒已成为我国 65 岁以上老年人因伤致死的首位原因&#xff08;来源&#xff1a;IT之家&#xff09;。 跌倒最容易发生在两个地方&#xff0c;卫生间和过道。主要可能是卫生间没有安装扶手&…

【案例】平面云

教程案例视频&#xff1a;Unity Shader Graph - 云教程 开发平台&#xff1a;Unity 2022 开发工具&#xff1a;Unity ShaderGraph   一、效果展示 二、ShaderGraph 路线图 三、案例分析 核心思路&#xff1a;使用 Noise&#xff08;噪声&#xff09;模拟云层状态   3.1 说明…

C++异步操作实现线程池

文章目录 std::future用法async函数promise::get_futurepackaged_task::get_future 线程池实现 std::future std::future是C11标准库中的一个模板类,表示异步操作的结果 当我们在进行多线程中使用异步任务时,std::future是用来帮我们在需要的时候获取任务执行的结果 他的一个…

基于spring boot的篮球论坛系统

作者&#xff1a;计算机搬砖家 开发技术&#xff1a;SpringBoot、php、Python、小程序、SSM、Vue、MySQL、JSP、ElementUI等&#xff0c;“文末源码”。 专栏推荐&#xff1a;SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏&#xff1a;Java精选实战项…

快停止这种使用U盘的行为!

前言 现在各行各业的小伙伴基本上都需要用电脑来办公了&#xff0c;你敢说你不需要用电脑办公&#xff1f; 啊哈哈哈&#xff0c;用iPad或者手机办公的也算。 有些小伙伴可能经常996&#xff0c;甚至有时候都是007。有时候到了下班时间&#xff0c;工作还没做完&#xff0c;…

图文深入理解Oracle DB企业级集中管理神器-GC的安装和部署

值此国庆佳节&#xff0c;深宅家中&#xff0c;闲来无事&#xff0c;就多写几篇博文。今天继续宅继续写。 本文承接上篇&#xff0c;介绍GC的安装和部署。咱们不急&#xff0c;慢慢来&#xff0c;饭要一口一口地吃才能吃得踏实自然。 限于篇幅&#xff0c;本节将重点介绍关键步…

VRRP协议个人理解+报文示例+典型配置-RFC2338/RFC3768/RFC5798/RFC9568

个人认为&#xff0c;理解报文就理解了协议。通过报文中的字段可以理解协议在交互过程中相关传递的信息&#xff0c;更加便于理解协议。 因此本文将在VRRP协议报文的基础上进行介绍。 VRRP协议发展 关于VRRPv2基本原理&#xff0c;可重点参考2004年发布的RFC3768-Virtual Ro…

深入理解NumPy库:常用函数详解与数组操作指南

在数据科学和数值计算领域&#xff0c;NumPy无疑是一个强大的工具&#xff0c;它为Python提供了高效的多维数 组处理能力。无论是进行数据分析、构建机器学习模型&#xff0c;还是进行复杂的科学计算&#xff0c;NumPy都是 不可或缺的核心库之一。 numpy.array 是 NumPy 库中…

UART通信—基于江科大源码基础进行的改进和解析

我就不讲理论了&#xff0c;CSDN上大佬属实多&#xff0c;我就只讲代码了&#xff0c;串口的基本理论&#xff0c;大家去看其他大佬写的吧 一、源文件的组成 1、包含的头文件 stm32f10x.h 是STM32F10x系列微控制器的标准外设库&#xff08;Standard Peripheral Library&…

【算法业务】数据驱动的用户增长实践、收益及思考

这篇内容是多年之前&#xff08;2020年&#xff09;的用户增长项目时自己写的总结&#xff0c;这里做一下对于实践和思考的回顾&#xff0c;便于知识的记录和经验分享&#xff0c;内容涉及用户增长理解、个性化推送系统框架、个性化推送问题建模、推送内容池构建、智能文案生成…

zotero使用koofr+google drive/onedrive同步

最早了解到这个思路是来自 知乎-【从零开始使用Zotero】(3) Zotero文献同步方式 和 How to Sync Zotero Files Using WebDAV and Google Drive with Koofr: A Step-by-Step Guide 虽然周围很多人都在用Readpaper这种web端的了&#xff0c;但是经常逛Arxiv而且zotero的web插…

MATLAB|电气互联系统有功-无功协同优化模型

目录 1 主要内容 模型示意图 目标函数 程序亮点 2 部分程序 3 程序结果 4 下载链接 1 主要内容 本程序基本复现《“碳中和”目标下电气互联系统有功-无功协同优化模型》&#xff0c;文献模型提供了一个很好的创新思路&#xff0c;把常规电气互联系统的调度和有功无功优化…