十、RGBA数据转NV21格式存储

news2024/7/6 18:32:17

1、介绍

首先为什么要去了解RGBA转NV21格式的,因为在软编码X264的时候就需要yuv格式作为输入源进行编码。

NV21格式的回顾:也是YUV420SP格式,存储两个plane,Y,VU交叉存储,内存大小为w * h + w * h/ 4 * 2=wh*1.5

再了解一下opengles的纹理怎么存储NV21数据:原来的RGBA数据大小为(w * h)*4 需要变成NV21的(w * h)1.5。则需要进行采样。原来RGBA的一行数据是4 * w(因为一个像素需要RGBA四个字节)但是现在NV21只有Y一个通道了,因此NV21的纹理大小宽应该需要w /4。那么根据总大小计算得知高应该要H *3 /2.可以如下设计:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eYV9Hiyl-1686050316326)(C:\Users\CreatWall_zhouwen\Desktop\pic\pic\nv210.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Z0S11seg-1686050316329)(C:\Users\CreatWall_zhouwen\Desktop\pic\pic\nv212.png)]

2、代码实践

对比之前的转YUYV一致,只有片段着色器和FBO的纹理大小和绘画时有部分不一致,其他都是相同的。

工程都使用了com.example.sixrgb2yuv 区分只用修改cmaket包含的cpp文件即可。

片段着色器

#version 300 es
precision mediump float;
layout(location = 0) out vec4 outColor;
in vec2 v_texCoord;
uniform sampler2D s_TextureMap;
uniform float u_offest;
//公式
//Y =  0.299R + 0.587G + 0.114B
//U = -0.147R - 0.289G + 0.436B
//V =  0.615R - 0.515G - 0.100B
const vec3 COEF_Y = vec3( 0.299,  0.587,  0.114);
const vec3 COEF_U = vec3(-0.147, -0.289,  0.436);
const vec3 COEF_V = vec3( 0.615, -0.515, -0.100);
const float UV_DIVIDE_LINE = 2.0 / 3.0;
void main() {
    vec2 texelOffset = vec2(u_offest, 0.0);//这边偏移量传值为1/width
    if(v_texCoord.y <= UV_DIVIDE_LINE) {
        vec2 texCoord = vec2(v_texCoord.x, v_texCoord.y * 3.0 / 2.0);
        vec4 color0 = texture(s_TextureMap, texCoord);
        vec4 color1 = texture(s_TextureMap, texCoord + texelOffset);
        vec4 color2 = texture(s_TextureMap, texCoord + texelOffset * 2.0);
        vec4 color3 = texture(s_TextureMap, texCoord + texelOffset * 3.0);
        float y0 = dot(color0.rgb, COEF_Y);
        float y1 = dot(color1.rgb, COEF_Y);
        float y2 = dot(color2.rgb, COEF_Y);
        float y3 = dot(color3.rgb, COEF_Y);
        outColor = vec4(y0, y1, y2, y3);
    }
    else{
        //不清楚为什么减UV_DIVIDE_LINE再乘以3
        vec2 texCoord = vec2(v_texCoord.x, (v_texCoord.y - UV_DIVIDE_LINE) * 3.0);
        vec4 color0 = texture(s_TextureMap, texCoord);
        vec4 color1 = texture(s_TextureMap, texCoord + texelOffset);
        vec4 color2 = texture(s_TextureMap, texCoord + texelOffset * 2.0);
        vec4 color3 = texture(s_TextureMap, texCoord + texelOffset * 3.0);
        float v0 = dot(color0.rgb, COEF_V) + 0.5;
        float u0 = dot(color1.rgb, COEF_U) + 0.5;
        float v1 = dot(color2.rgb, COEF_V) + 0.5;
        float u1 = dot(color3.rgb, COEF_U) + 0.5;
        outColor = vec4(v0, u0, v1, u1);
    }
}

RGB2NV21.cpp

//
// Created by CreatWall_zhouwen on 2023/4/28.
//

#include <stdio.h>
#include "RGB2NV21.h"
#include "Util.h"
#include "GLUtil.h"
#include <malloc.h>
#include <string.h>
#include <unistd.h>
#include "sys/stat.h"
#include "stdint.h"
RGB2NV21* m_pContext = nullptr;
#define TAG "RGB2NV21"
//顶点坐标
GLfloat vVertices[] = {
        -1.0f, -1.0f, 0.0f,
        1.0f, -1.0f, 0.0f,
        -1.0f,  1.0f, 0.0f,
        1.0f,  1.0f, 0.0f,
};
//纹理坐标

GLfloat vFboTexCoors[] = {
        0.0f, 0.0f,
        1.0f, 0.0f,
        0.0f, 1.0f,
        1.0f, 1.0f,
};
GLushort indices[] = { 0, 1, 2, 1, 3, 2 };//三角形的索引数组

/*
 *
-1.0f, -1.0f, 0.0f,
        1.0f, -1.0f, 0.0f,
        -1.0f,  1.0f, 0.0f,
        1.0f,  1.0f, 0.0f,
//纹理坐标
GLfloat vFboTexCoors[] = {
        0.0f, 1.0f,
        1.0f, 1.0f,
        0.0f, 0.0f,
        1.0f, 0.0f,
};
GLushort indices[] = { 0, 1, 2, 1, 3, 2 };//三角形的索引数组
*/
RGB2NV21::RGB2NV21() {
     m_FboVertexShader = GL_NONE;//FBO的顶点着色器和片段着色器
     m_FboFragmentShader= GL_NONE;
     m_FboProgramObj= GL_NONE;//FBO工程ID
     m_ImageTextureId= GL_NONE;//图片数据的纹理ID
     m_FboTextureId= GL_NONE;//FBO绑定的空数据纹理ID
     m_FboSamplerLoc= GL_NONE;//FBO片段着色器中的采样器值的位置
     m_FboId= GL_NONE;//FBO的ID
     m_VaoId= GL_NONE;//存放顶点数据
     m_VboIds[0]= GL_NONE;//0表示顶点坐标缓冲区,1表示离屏渲染纹理坐标缓冲区,2表示纹理索引坐标缓冲区

     m_eglConf= GL_NONE;
     m_eglSurface= GL_NONE;
     m_eglCtx= GL_NONE;
     m_eglDisplay= GL_NONE;
}

RGB2NV21::~RGB2NV21() {

}

int RGB2NV21::CreateGlesEnv() {
    // EGL config attributes
    const EGLint confAttr[] =
            {
                    EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT_KHR,
                    EGL_SURFACE_TYPE,EGL_PBUFFER_BIT,//EGL_WINDOW_BIT EGL_PBUFFER_BIT we will create a pixelbuffer surface
                    EGL_RED_SIZE,   8,
                    EGL_GREEN_SIZE, 8,
                    EGL_BLUE_SIZE,  8,
                    EGL_ALPHA_SIZE, 8,// if you need the alpha channel
                    EGL_DEPTH_SIZE, 16,// if you need the depth buffer
                    EGL_STENCIL_SIZE,8,
                    EGL_NONE
            };

    // EGL context attributes
    const EGLint ctxAttr[] = {
            EGL_CONTEXT_CLIENT_VERSION, 2,
            EGL_NONE
    };

    // surface attributes
    // the surface size is set to the input frame size
    const EGLint surfaceAttr[] = {
            EGL_WIDTH, 1,
            EGL_HEIGHT,1,
            EGL_NONE
    };
    EGLint eglMajVers, eglMinVers;
    EGLint numConfigs;

    int resultCode = 0;
    do
    {
        //1. 获取 EGLDisplay 对象,建立与本地窗口系统的连接
        m_eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
        if(m_eglDisplay == EGL_NO_DISPLAY)
        {
            //Unable to open connection to local windowing system
            LOGD("EGLRender::CreateGlesEnv Unable to open connection to local windowing system");
            resultCode = -1;
            break;
        }

        //2. 初始化 EGL 方法
        if(!eglInitialize(m_eglDisplay, &eglMajVers, &eglMinVers))
        {
            // Unable to initialize EGL. Handle and recover
            LOGD("EGLRender::CreateGlesEnv Unable to initialize EGL");
            resultCode = -1;
            break;
        }

        LOGD("EGLRender::CreateGlesEnv EGL init with version %d.%d", eglMajVers, eglMinVers);

        //3. 获取 EGLConfig 对象,确定渲染表面的配置信息
        if(!eglChooseConfig(m_eglDisplay, confAttr, &m_eglConf, 1, &numConfigs))
        {
            LOGD("EGLRender::CreateGlesEnv some config is wrong");
            resultCode = -1;
            break;
        }

        //4. 创建渲染表面 EGLSurface, 使用 eglCreatePbufferSurface 创建屏幕外渲染区域
        m_eglSurface = eglCreatePbufferSurface(m_eglDisplay, m_eglConf, surfaceAttr);
        if(m_eglSurface == EGL_NO_SURFACE)
        {
            switch(eglGetError())
            {
                case EGL_BAD_ALLOC:
                    // Not enough resources available. Handle and recover
                    LOGD("EGLRender::CreateGlesEnv Not enough resources available");
                    break;
                case EGL_BAD_CONFIG:
                    // Verify that provided EGLConfig is valid
                    LOGD("EGLRender::CreateGlesEnv provided EGLConfig is invalid");
                    break;
                case EGL_BAD_PARAMETER:
                    // Verify that the EGL_WIDTH and EGL_HEIGHT are
                    // non-negative values
                    LOGD("EGLRender::CreateGlesEnv provided EGL_WIDTH and EGL_HEIGHT is invalid");
                    break;
                case EGL_BAD_MATCH:
                    // Check window and EGLConfig attributes to determine
                    // compatibility and pbuffer-texture parameters
                    LOGD("EGLRender::CreateGlesEnv Check window and EGLConfig attributes");
                    break;
            }
        }

        //5. 创建渲染上下文 EGLContext
        m_eglCtx = eglCreateContext(m_eglDisplay, m_eglConf, EGL_NO_CONTEXT, ctxAttr);
        if(m_eglCtx == EGL_NO_CONTEXT)
        {
            EGLint error = eglGetError();
            if(error == EGL_BAD_CONFIG)
            {
                // Handle error and recover
                LOGD("EGLRender::CreateGlesEnv EGL_BAD_CONFIG");
                resultCode = -1;
                break;
            }
        }

        //6. 绑定上下文
        if(!eglMakeCurrent(m_eglDisplay, m_eglSurface, m_eglSurface, m_eglCtx))
        {
            LOGD("EGLRender::CreateGlesEnv MakeCurrent failed");
            resultCode = -1;
            break;
        }
        LOGD("EGLRender::CreateGlesEnv initialize success!");
    }
    while (false);

    if (resultCode != 0)
    {
        LOGD("EGLRender::CreateGlesEnv fail");
    }
    LOGD("EGLRender::CreateGlesEnv Success");
    return resultCode;
}

void RGB2NV21::CreateProgram(const char *ver, const char *fragfbo) {
    LOGD("CreateProgram Enter");
    // 编译链接用于离屏渲染的着色器程序
    m_FboProgramObj = CreateGLProgram(ver, fragfbo, m_FboVertexShader, m_FboFragmentShader);
    if (m_FboProgramObj == GL_NONE)
    {
        LOGD("FBOSample::Init m_ProgramObj == GL_NONE");
        return;
    }
    LOGD("CreateGLProgram Success");

    //获取片段着色器中s_TextureMap的属性位置,编译后期指定是哪个纹理
    m_FboSamplerLoc = glGetUniformLocation(m_FboProgramObj, "s_TextureMap");
    LOGD("glGetUniformLocation Success");

    //生成VBO 加载顶点数据和索引数据
    glGenBuffers(4, m_VboIds);
    glBindBuffer(GL_ARRAY_BUFFER, m_VboIds[0]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vVertices), vVertices, GL_STATIC_DRAW);
    glBindBuffer(GL_ARRAY_BUFFER, m_VboIds[1]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vFboTexCoors), vFboTexCoors, GL_STATIC_DRAW);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_VboIds[2]);//最后一个为纹理的索引缓冲数据
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
    LOGD("glGenBuffers Success");

    //初始化离屏渲染的VAO
    glGenVertexArrays(1, &m_VaoId);
    glBindVertexArray(m_VaoId);
    glBindBuffer(GL_ARRAY_BUFFER, m_VboIds[0]);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (const void *)0);
    glBindBuffer(GL_ARRAY_BUFFER, GL_NONE);
    glBindBuffer(GL_ARRAY_BUFFER, m_VboIds[1]);
    glEnableVertexAttribArray(1);
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), (const void *)0);
    glBindBuffer(GL_ARRAY_BUFFER, GL_NONE);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_VboIds[2]);
    glBindVertexArray(GL_NONE);
    LOGD("m_VaoId[0] Success");

    //创建并初始化图形纹理
    glGenTextures(1, &m_ImageTextureId);
    glBindTexture(GL_TEXTURE_2D, m_ImageTextureId);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);//重复纹理的填充方式
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);//缩小时线性插值
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);//放到就是线性
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, texturewidth, textureheight, 0, GL_RGB, GL_UNSIGNED_BYTE, texturedata);
    LOGD("CreateProgram %s", texturedata);
    glGenerateMipmap(GL_TEXTURE_2D);//为当前绑定的纹理自动生成所有需要的多级渐远纹理
    glBindTexture(GL_TEXTURE_2D, GL_NONE);
    LOGD("m_ImageTextureId Success");
    //创建离屏的纹理,不绑定数据值申请内存
    glGenTextures(1, &m_FboTextureId);
    glBindTexture(GL_TEXTURE_2D, m_FboTextureId);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    //最后输出YUYV数据格式,则宽缩短一半了。   这个需要使用到RGBA格式的,
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texturewidth/4, textureheight*3 / 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
    glBindTexture(GL_TEXTURE_2D, GL_NONE);
    LOGD("m_FboTextureId Success");

    //创建并初始化FBO,帧缓冲
    glGenFramebuffers(1, &m_FboId);
    glBindFramebuffer(GL_FRAMEBUFFER, m_FboId);//绑定帧缓冲
    glBindTexture(GL_TEXTURE_2D, m_FboTextureId);//激活这个m_FboTextureId纹理绑定GL_TEXTURE_2D
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_FboTextureId, 0);//纹理附加到帧缓冲
    if (glCheckFramebufferStatus(GL_FRAMEBUFFER)!= GL_FRAMEBUFFER_COMPLETE) {
        LOGD("FBOSample::CreateFrameBufferObj glCheckFramebufferStatus status != GL_FRAMEBUFFER_COMPLETE");
        return ;
    }
    glBindTexture(GL_TEXTURE_2D, GL_NONE);
    glBindFramebuffer(GL_FRAMEBUFFER, GL_NONE);
    LOGD("m_FboId Success");
}

void RGB2NV21::Draw() {
    LOGD("Draw Enter");
    // 离屏渲染
    glPixelStorei(GL_UNPACK_ALIGNMENT,1);
    glViewport(0, 0, texturewidth/4, textureheight*3 / 2);
    glUseProgram(m_FboProgramObj);
    glBindFramebuffer(GL_FRAMEBUFFER, m_FboId);
    glBindVertexArray(m_VaoId);
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, m_ImageTextureId);
    glUniform1i(m_FboSamplerLoc, 0);
    float texelOffset = (float) (1.f / (float) texturewidth);
    glUniform1f(glGetUniformLocation(m_FboProgramObj, "u_offest"), texelOffset);
    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, (const void *)0);
    glBindVertexArray(GL_NONE);
    glBindTexture(GL_TEXTURE_2D, GL_NONE);
    LOGD("Draw success");
    uint8_t *pBuffer = new uint8_t[texturewidth*textureheight * 3 / 2];
    uint8_t *p = new uint8_t[texturewidth*textureheight * 3 / 2];
    uint8_t *p1 = p + texturewidth*textureheight;
    glReadPixels(0, 0, texturewidth / 4, textureheight*3 / 2, GL_RGBA, GL_UNSIGNED_BYTE, pBuffer);
    //p = pBuffer;
    //p1 = pBuffer+ texturewidth*textureheight;
    //写文件
    const char *imgPath= "/data/data/com.example.sixrgb2yuv/RGB2NV21.yuv";
    FILE *fp = fopen(imgPath, "wb");
    if(fp == NULL)
    {
        LOGD("fopen error");
        glBindFramebuffer(GL_FRAMEBUFFER, 0);

        return ;
    }
    //fwrite(p,1, texturewidth*textureheight,  fp);
    //fwrite(p1,1, texturewidth*textureheight/2,  fp);
    fwrite(pBuffer,1, texturewidth*textureheight *  3 / 2,  fp);
    fclose(fp);
    glBindFramebuffer(GL_FRAMEBUFFER, 0);
    LOGD("Draw End");
}


void RGB2NV21::getTexturedata(unsigned char *data, int width, int height) {
     texturedata = data;
     texturewidth = width;
     textureheight = height;
     LOGD("getTexturedata Success %s", texturedata);
}


RGB2NV21 *RGB2NV21::GetInstance() {
     if (m_pContext == nullptr)
     {
          m_pContext = new RGB2NV21();
     }
     return m_pContext;
}

void RGB2NV21::DestroyInstance() {
     if (m_pContext)
     {
          delete m_pContext;
          m_pContext = nullptr;
     }
}



void RGB2NV21::UnInit() {
     LOGD("EGLDraw::UnInit");
     if (m_FboProgramObj)
     {
          glDeleteProgram(m_FboProgramObj);
          m_FboProgramObj = GL_NONE;
     }
     if (m_FboTextureId)
     {
          glDeleteTextures(1, &m_FboTextureId);
          m_FboTextureId = GL_NONE;
     }
     if (m_VboIds[0])
     {
          glDeleteBuffers(3, m_VboIds);
          m_VboIds[0] = GL_NONE;
          m_VboIds[1] = GL_NONE;
          m_VboIds[2] = GL_NONE;

     }
     if (m_VaoId)
     {
          glDeleteVertexArrays(1, &m_VaoId);
          m_VaoId = GL_NONE;
     }
     if (m_FboId)
     {
          glDeleteFramebuffers(1, &m_FboId);
          m_FboId = GL_NONE;
     }

     //8. 释放 EGL 环境
     if (m_eglDisplay != EGL_NO_DISPLAY) {
          eglMakeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
          eglDestroyContext(m_eglDisplay, m_eglCtx);
          eglDestroySurface(m_eglDisplay, m_eglSurface);
          eglReleaseThread();
          eglTerminate(m_eglDisplay);
     }
}

疑惑:

片段着色器的处理有部分没有理解

输出的NV21图形对称了,尝试修改纹理坐标也没有修改正确,怀疑问题是不是BMP图片的位图影响的,这里图片为24位的
在这里插入图片描述

参考链接:

Opengl ES之RGB转NV21 https://www.cnblogs.com/goFlyer/p/17055371.html

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

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

相关文章

力扣高频SQL50题(基础版)——第七天

力扣高频SQL50题(基础版)——第七天 1 查询结果的质量与占比 1.1 题目内容 1.1.1 基本题目信息 1.1.2 示例输入输出 1.2 示例sql语句 SELECT q.query_name,ROUND(AVG(q.rating/q.position),2) quality, ROUND(100*(SELECT count(*) FROM Queries WHERE rating<3 AND que…

国产品牌:中国牙科市场的美好未来

牙菌斑是口腔疾病主要元凶&#xff0c;我国口腔患者人数逐年增加。根据国家卫健委的资料&#xff0c;常见的口腔疾病主要是由附着在牙齿上的牙菌斑引起&#xff0c;因此&#xff0c;口腔护理主要达到清除牙菌斑、保护牙齿及牙周健康的目的。根据天猫发布的《2021 天猫口腔护理消…

【SpinalHDL快速入门】4.4、基本类型之Enum

文章目录 1.1、描述1.2、声明1.2.1、编码1.2.2、示例 1.3、运算符1.3.1、比较&#xff08;Comparison&#xff09;1.3.2、类型&#xff08;Types&#xff09;1.3.3、类型转换 1.1、描述 枚举类型对应于命名值列表。 1.2、声明 枚举数据类型的声明如下&#xff1a; object E…

vscode搭建Python环境

文章目录 安装Python解释器vscode 所需插件PythonCode Runner vscode调试Python官网的中文文档 安装Python解释器 打开Python官网 https://www.python.org/ 在 Downloads 下面选择自己的对应系统&#xff0c;本文以 Windows 为例 可以选择最新版本 下载可执行文件类型的安…

【Linux服务器编程总结】网络编程基础知识 (udp初级)

一.预备知识 1.主机字节序和网络字节序: 其实本质就是大小端。通常在网络传输的时候会将要发送的数据转同一转换成大端后再发送。在linux中提供了如下四个函数进行大小端转换。 2. 网络套接字&#xff1a; 我们在网络编程的时候会使用到socktet 套接字。对此我们需要了解so…

SQL语句之DQL语言(一)

说明&#xff1a;DQL&#xff08;Data Query Language&#xff0c;数据查询语言&#xff09;&#xff0c;用来查询数据库表中的记录。有的书中&#xff0c;会把DQL语言放入到DML&#xff08;Data Manipulation Language&#xff0c;数据操作语言&#xff1a;数据的增删改&#…

初识TypeScript -基础一

前言 在开始工作之前&#xff0c;就听朋友提过TypeScript&#xff0c;之前也没多想学习&#xff0c;直到vue3出来之后&#xff0c;感觉TypeScript 后面会成为主流&#xff0c;只能硬着头皮学学吧。 读完本片文章&#xff0c;你会收获 1、TypeScript的历史及其优势 2、TypeScri…

Day_39关键路径

目录 一. 关于关键路径 1. 有向无环图 2. AOV网 3. 拓补排序 4. 关键路径 二. 如何实现寻找关键路径 三. 关键路径的代码实现 1. 正向计算 1.1 计算每个节点的入度 1.2 拓扑排序&#xff08;计算每个节点最早开始的时间&#xff09; 2. 反向计算 2.1 计算每个节点的出度&…

基于jupyter的线性回归练习

文章目录 练习1&#xff1a;线性回归介绍1 实现简单示例函数1.1 提交解决方案 2 单变量线性回归2.1 绘制数据2.2 梯度下降2.2.1 更新公式2.2.2 实现2.2.3 计算成本J(θ)2.2.4 梯度下降 2.3 可视化成本函数 选做练习3 多变量线性回归3.1 特征标准化3.2 梯度下降 总结 练习1&…

第六章:多表查询

第六章&#xff1a;多表查询 ​ 多表查询&#xff0c;也称为关联查询&#xff0c;指两个或更多个表一起完成查询操作。 ​ 前提条件&#xff1a;这些一起查询的表之间是有关系的(一对一、一对多)&#xff0c;它们之间一定是有关联字段&#xff0c;这个关联字段可能建立了外键…

SciencePub学术 | 人工智能类重点SCIEI征稿中

SciencePub学术 刊源推荐: 人工智能类重点SCI&EI征稿中&#xff01;影响因子高&#xff0c;对国人友好。信息如下&#xff0c;录满为止&#xff1a; 一、期刊概况&#xff1a; 人工智能类重点SCI&EI 【期刊简介】IF&#xff1a;7.5-8.0&#xff0c;JCR1区&#xff0…

chatgpt赋能python:Python如何获取图片的尺寸

Python如何获取图片的尺寸 如果你在使用Python编程&#xff0c;常常需要获取图片的尺寸&#xff0c;本文将介绍如何使用Python获取图片的尺寸&#xff0c;同时还会介绍一些常用的Python库用于图像处理。 PIL库 PIL&#xff08;Python Imaging Library&#xff09;是Python中…

chatgpt赋能python:Python中如何设置空格

Python中如何设置空格 作为一门流行的编程语言&#xff0c;Python被广泛地应用于各种领域。在编写Python代码时&#xff0c;空格的使用非常重要。适当的空格设置可以让代码易读易懂&#xff0c;同时也有助于提高代码的可维护性和可重用性。 什么是空格 在Python中&#xff0…

shell脚本:循环结束语句二

shell脚本-循环结束语句二 二、循环结束语句&#xff1a;1.break&#xff1a;跳出循环。2.continue&#xff1a;3.while&#xff1a;4.until&#xff1a;条件不成立时&#xff0c;跳出循环。5.总结&#xff1a; 三、操作演练&#xff1a; 二、循环结束语句&#xff1a; 1.brea…

QT CTK插件开发(六) 多对一插件

CTK在软件的开发过程中可以很好的降低复杂性、使用 CTK Plugin Framework 提供统一的框架来进行开发增加了复用性 将同一功能打包可以提供多个应用程序使用避免重复性工作、可以进行版本控制提供了良好的版本更新迭代需求、并且支持动态热拔插 动态更新、开发更加简单快捷 方便…

基于jupyter的逻辑回归练习

文章目录 练习2&#xff1a;逻辑回归介绍1 Logistic回归1.1 数据可视化1.2 实现1.2.1 Sigmoid函数1.2.2 代价函数和梯度1.2.2.1 代价函数1.2.2.2 梯度下降 1.2.3 寻找最优参数1.2.4 评估逻辑回归 2 正则化逻辑回归2.1 数据可视化2.2 特征映射2.3 代价函数和梯度 2.4 寻找最优参…

腾讯云618云服务器优惠活动价格表

2023年腾讯云618年中促销活动已经正式开始了&#xff0c;腾讯云多款云服务都有特惠&#xff0c;下面给大家分享腾讯云618云服务器优惠活动价格表&#xff0c;记得抓住这次上云好时机&#xff01; 目录 一、腾讯云618活动入口 二、轻量应用服务器优惠价格表 三、CVM云服务器优…

【连续介质力学】二阶张量的图像表示

二阶张量在特定方向的投影 法向和切向分量 二阶张量T投影到 n ^ \hat n n^方向的结果是 t ⃗ ( n ^ ) T ⋅ n ^ \vec t^{(\hat n)}T \cdot \hat n t (n^)T⋅n^&#xff0c;其中 t ⃗ ( n ^ ) \vec t^{(\hat n)} t (n^)可以分解成&#xff1a; t ⃗ ( n ^ ) T ⃗ N T ⃗ S…

指针(三)

文章内容 1. 字符指针 2. 数组指针 3. 指针数组 文章内容 1. 字符指针 指针的概念&#xff1a; 1. 指针就是个变量&#xff0c;用来存放地址&#xff0c;地址唯一标识一块内存空间。 2. 指针的大小是固定的4/8个字节&#xff08;32位平台/64位平台&#xff09;。 3. 指针…

适配器stack和queue

目录 什么是适配器 模拟实现stack stack的特性 STL中stack的基本框架 接口实现 模拟实现queue queue的特性 STL中queue的框架 什么是适配器 适配器&#xff1a;所谓适配&#xff0c;适配的是容器(vector,list,deque....) 也就是不管是什么容器&#xff0c;都可以套用适…