融媒体服务中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);
}
如下图所示,存的图像是倒立镜像的,实际上是正立的三角形,还没有将视频附上去,工作量有些大,等到下一个文章再写。
相关文章:

融媒体服务中PBO进行多重采样抗锯齿(MSAA)
如果不理解pbo 那先去了解概念,在此不再解释,这是我为了做融合服务器viewpointserver做的一部分工作,融合服务器的功能是将三维和流媒体,AI融合在一起,viewpointserver会直接读取三维工程的文件,同时融合rt…...

说说BPMN概念及应用
BPMN(Business Process Modeling and Notation)即业务流程建模与标注,是一种由OMG(Object Management Group,对象管理组织)制定的业务流程建模语言。以下是对BPMN标准的详细解释: 一、BPMN的起…...

【微服务】初识(day1)
基础概念 集群 集群是将一个系统完整的部署到多个服务器,每个服务器提供系统的所有服务,多个服务器可以通过负载均衡完成任务,每个服务器都可以称为集群的节点。 分布式 分布式是将一个系统拆分为多个子系统,多个子系统部署在…...

15分钟学 Python 第40天:Python 爬虫入门(六)第一篇
Day40 :Python 爬取豆瓣网前一百的电影信息 1. 项目背景 在这个项目中,我们将学习如何利用 Python 爬虫技术从豆瓣网抓取前一百部电影的信息。通过这一练习,您将掌握网页抓取的基本流程,包括发送请求、解析HTML、存储数据等核心…...

分层解耦-05.IOCDI-DI详解
一.依赖注入的注解 在我们的项目中,EmpService的实现类有两个,分别是EmpServiceA和EmpServiceB。这两个实现类都加上Service注解。我们运行程序,就会报错。 这是因为我们依赖注入的注解Autowired默认是按照类型来寻找bean对象的进行依赖注入…...

HCIP-HarmonyOS Application Developer 习题(六)
(多选)1、Harmonyos多窗口交互能力提供了以下哪几种交互方式? A. 平行视界 B.全局消息通知 C.分屏 D.悬浮窗 答案:ACD 分析:系统提供了悬浮窗、分屏、平行视界三种多窗口交互,为用户在大屏幕设备上的多任务并行、便捷…...

【电路基础 · 3】实际电压源 实际电流源;两种电源的等效情况;戴维南模型 诺顿模型(自用)
总览 1.实际电源的两种模型和它们的等效变换 2.两种电源的等效情况 3.戴维南模型 && 诺顿模型 一、实际电源的两种模型和它们的等效变换 1.实际电压源 实际电压源不允许短路。因为它的内阻太小,如果短路,电流很大,可能会烧毁电源…...

案例-猜数字游戏
文章目录 效果展示初始画面演示视频 代码区 效果展示 初始画面 演示视频 猜数字游戏 代码区 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width,…...

POI数据的处理与分析
POI概念 POI(Point of Interest,兴趣点)数据指的是地理空间数据中的一类,表示某一具体地点或位置的信息。通常,这些数据包含位置坐标(经纬度)、名称、地址、类别和其他相关信息。POI 数据广泛应…...
ansible部分模块学习
ansible模块学习 copy模块 copy模块srcsource 源⽂件destdestination ⽬标backupbackupyes 则会在覆盖前进⾏备份mode修改权限owner修改为指定所有者group修改为指定⽤户组 案例1:传输/root/work/scripts/net-tools-install.sh⽂件到/opt/net-tools-install.sh …...

数据库(MySQL):使用命令从零开始在Navicat创建一个数据库及其数据表(二).设置主键自增等特点
前言 在上一节中,主要介绍了 Navicat Premium 17 的使用以及创建一个基础的表格。当时只设置了给数据表补充字段,没有设置给数据表删除字段。现在补充一下。 ALTER TABLE student ADD test int(4); 给名为 student 的数据表添加 test 列…...

SQL第13课——创建高级联结
本课讲另外一些联结(含义和使用方法),如何使用表别名,如何对被联结的表使用聚集函数。 13.1 使用表别名 第7课中使用别名引用被检索的表列,给列起别名的语法如下: SQL除了可以对列名和计算字段使用别名&a…...

订阅ROS2中相机的相关话题并保存RGB、深度和点云图
系统:Ubuntu22.04 ROS2版本:ROS2 humble 1.订阅ROS2中相机的相关话题并保存RGB图、深度图和点云图 ros2 topic list/stellar_1/rgb/image_raw /camera/depth/image_raw /stellar_1/points2CMakeLists.txt cmake_minimum_required(VERSION 3.15) projec…...

Open WebUI | 自托管的类 ChatGPT 网站
Open WebUI 是一个扩展性强、功能丰富且用户友好的自托管 WebUI,旨在完全离线操作。它支持各种 LLM 服务,包括 Ollama 和 OpenAI 兼容的 API。该项目在 GitHub 上已有 38k 星,非常受欢迎。 功能介绍 废话不多说,上图!…...

【Python】Python知识总结浅析
Python是一种高级编程语言,由Guido van Rossum于1991年首次发布。它以简洁的语法和强大的功能著称,适用于多种应用场景,包括Web开发、数据分析、人工智能、自动化脚本等。 易于学习和使用:Python的语法简洁明了,适合初…...
c#代码介绍23种设计模式_20策略者模式
目录 1、策略模式的定义 2、策略模式的结构 3、涉及到三个角色: 4、策略者模式在.NET中应用 5、策略者模式的适用场景 6、策略者模式的优缺点 7、实现思路 在现实生活中,策略模式的例子也非常常见,例如,中国的所得税,分为企业所得税、外商投资企业或外商企业所得税…...

FPGA-UART串口接收模块的理解
UART串口接收模块 背景 在之前就有写过关于串口模块的文章——《串口RS232的学习》。工作后很多项目都会用到串口模块,又来重新理解一下FPGA串口接收的代码思路。 关于串口相关的参数,以及在文章《串口RS232的学习》中已有详细的描述,这里就…...

复习HTML(基础)
目录 HTML含义 HTML作用 HTML的常用元素 元素的特点 元素的分类 1 是否嵌套关系 2 是否独占一行 块元素:独占一行 行内元素:共享一行 行内元素与块级元素的转换 3是否有结束标签 常用标签 1 标题标签:有六级 我们用h1 ~h6 表…...

Linux聊天集群开发之环境准备
一.windows下远程操作Linux 第一步:在Linux终端下配置openssh,输入netstate -tanp,查看ssh服务是否启动,默认端口22.。 注:如果openssh服务,则需下载。输入命令ps -e|grep ssh, 查看如否配有, ssh-agent …...

can 总线入门———can简介硬件电路
文章目录 0. 前言1. CAN简介2. 主流通讯协议对比3. CAN 硬件电路4. CAN 电平标准5. CAN 收发器 0. 前言 博客内容来自B站上CAN总线入门教程视频讲解,博客中的插图和内容均为视频中的内容。视频链接 CAN总线入门教程 1. CAN简介 先来看看一它名字的意思,…...

基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真
目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销,平衡网络负载,延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...

Redis相关知识总结(缓存雪崩,缓存穿透,缓存击穿,Redis实现分布式锁,如何保持数据库和缓存一致)
文章目录 1.什么是Redis?2.为什么要使用redis作为mysql的缓存?3.什么是缓存雪崩、缓存穿透、缓存击穿?3.1缓存雪崩3.1.1 大量缓存同时过期3.1.2 Redis宕机 3.2 缓存击穿3.3 缓存穿透3.4 总结 4. 数据库和缓存如何保持一致性5. Redis实现分布式…...

相机Camera日志实例分析之二:相机Camx【专业模式开启直方图拍照】单帧流程日志详解
【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了: 这一篇我们开始讲: 目录 一、场景操作步骤 二、日志基础关键字分级如下 三、场景日志如下: 一、场景操作步骤 操作步…...

循环冗余码校验CRC码 算法步骤+详细实例计算
通信过程:(白话解释) 我们将原始待发送的消息称为 M M M,依据发送接收消息双方约定的生成多项式 G ( x ) G(x) G(x)(意思就是 G ( x ) G(x) G(x) 是已知的)࿰…...

MODBUS TCP转CANopen 技术赋能高效协同作业
在现代工业自动化领域,MODBUS TCP和CANopen两种通讯协议因其稳定性和高效性被广泛应用于各种设备和系统中。而随着科技的不断进步,这两种通讯协议也正在被逐步融合,形成了一种新型的通讯方式——开疆智能MODBUS TCP转CANopen网关KJ-TCPC-CANP…...

智能仓储的未来:自动化、AI与数据分析如何重塑物流中心
当仓库学会“思考”,物流的终极形态正在诞生 想象这样的场景: 凌晨3点,某物流中心灯火通明却空无一人。AGV机器人集群根据实时订单动态规划路径;AI视觉系统在0.1秒内扫描包裹信息;数字孪生平台正模拟次日峰值流量压力…...
【碎碎念】宝可梦 Mesh GO : 基于MESH网络的口袋妖怪 宝可梦GO游戏自组网系统
目录 游戏说明《宝可梦 Mesh GO》 —— 局域宝可梦探索Pokmon GO 类游戏核心理念应用场景Mesh 特性 宝可梦玩法融合设计游戏构想要素1. 地图探索(基于物理空间 广播范围)2. 野生宝可梦生成与广播3. 对战系统4. 道具与通信5. 延伸玩法 安全性设计 技术选…...

智能分布式爬虫的数据处理流水线优化:基于深度强化学习的数据质量控制
在数字化浪潮席卷全球的今天,数据已成为企业和研究机构的核心资产。智能分布式爬虫作为高效的数据采集工具,在大规模数据获取中发挥着关键作用。然而,传统的数据处理流水线在面对复杂多变的网络环境和海量异构数据时,常出现数据质…...

SiFli 52把Imagie图片,Font字体资源放在指定位置,编译成指定img.bin和font.bin的问题
分区配置 (ptab.json) img 属性介绍: img 属性指定分区存放的 image 名称,指定的 image 名称必须是当前工程生成的 binary 。 如果 binary 有多个文件,则以 proj_name:binary_name 格式指定文件名, proj_name 为工程 名&…...
比较数据迁移后MySQL数据库和OceanBase数据仓库中的表
设计一个MySQL数据库和OceanBase数据仓库的表数据比较的详细程序流程,两张表是相同的结构,都有整型主键id字段,需要每次从数据库分批取得2000条数据,用于比较,比较操作的同时可以再取2000条数据,等上一次比较完成之后,开始比较,直到比较完所有的数据。比较操作需要比较…...