stb_image简单使用

简介stb_image

stb_image 是一个非常轻量级的、单文件的图像加载库,用于加载和解码多种图像格式(如BMP、JPEG、PNG、GIF等)的图像数据。它由Sean T. Barrett开发,并以公共领域(Public Domain)许可发布,因此可以自由地用于商业和非商业项目

stb_image 提供了简单易用的接口,使得在应用程序中加载图像变得非常方便。只需包含单个头文件stb_image.h,就可以使用其中的函数来加载图像文件并返回解码后的像素数据

主要特点和功能包括:

支持多种常见的图像格式:stb_image 支持加载和解码常见的图像格式,包括 BMP、JPEG、PNG、GIF、HDR、TGA等。这使得开发者可以方便地加载各种格式的图像数据。

简单易用的接口:stb_image 提供了简洁而易用的函数接口,如 stbi_load 用于加载图像文件,stbi_image_free用于释放图像数据内存等。

支持透明通道:对于支持透明通道的图像格式(如PNG),stb_image 可以正确解码并返回带有透明度信息的像素数据。

轻量级、单文件:stb_image是一个非常轻量级的库,整个功能被包含在一个单独的头文件中,因此非常容易集成到项目中,无需复杂的配置和依赖。

下载:

git clone https://github.com/nothings/stb.git

git clone https://github.com/nothings/stb.git

我们下载得到的目录:
在这里插入图片描述

实际需要移植到我们工程里面的:
在这里插入图片描述

接口学习

stbi_load

stbi_load 函数从指定的文件加载图像数据,并返回一个指向图像数据的指针

STBIDEF stbi_uc *stbi_load(char const *filename, int *x, int *y, int *comp, int req_comp)
{
   FILE *f = stbi__fopen(filename, "rb");
   unsigned char *result;
   if (!f) return stbi__errpuc("can't fopen", "Unable to open file");
   result = stbi_load_from_file(f,x,y,comp,req_comp);
   fclose(f);
   return result;
}

filename:要加载的图像文件的路径和名称。

x:用于存储加载图像的宽度(以像素为单位)的指针变量。

y:用于存储加载图像的高度(以像素为单位)的指针变量。

comp:用于存储加载图像的颜色通道数(例如,RGB 图像为 3)的指针变量。

req_comp:请求加载图像的颜色通道数,可以指定为期望的通道数,或者使用特定的值 0,表示保持原始通道数。

函数内容:
使用 stbi__fopen 函数以二进制只读模式打开指定的图像文件。
检查文件是否成功打开,如果打开失败,则返回错误信息。
调用 stbi_load_from_file 函数,从打开的文件中读取图像数据,并将结果保存在 result 变量中。
关闭打开的文件。
返回图像数据的指针(如果加载成功)或错误信息的指针(如果加载失败)

stbir_resize

stbir_resize 函数将输入图像调整大小,并将结果存储在输出图像中

STBIRDEF int stbir_resize(         const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
                                         void *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
                                   stbir_datatype datatype,
                                   int num_channels, int alpha_channel, int flags,
                                   stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical,
                                   stbir_filter filter_horizontal,  stbir_filter filter_vertical,
                                   stbir_colorspace space, void *alloc_context)
{
    return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes,
        output_pixels, output_w, output_h, output_stride_in_bytes,
        0,0,1,1,NULL,num_channels,alpha_channel,flags, datatype, filter_horizontal, filter_vertical,
        edge_mode_horizontal, edge_mode_vertical, space);
}

input_pixels:指向输入图像数据的指针。
input_w:输入图像的宽度(以像素为单位)。
input_h:输入图像的高度(以像素为单位)。
input_stride_in_bytes:输入图像每行的字节步长(即每行像素数据占用的字节数)。
output_pixels:指向输出图像数据的指针。
output_w:输出图像的目标宽度(以像素为单位)。
output_h:输出图像的目标高度(以像素为单位)。
output_stride_in_bytes:输出图像每行的字节步长。
datatype:输入和输出图像的数据类型(例如,STBIR_TYPE_UINT8 表示无符号 8 位整数)。
num_channels:输入和输出图像的通道数。
alpha_channel:指定图像的 Alpha 通道索引(如果存在)。
flags:附加的处理标志。
edge_mode_horizontal 和 edge_mode_vertical:指定水平和垂直边缘处理模式。
filter_horizontal 和 filter_vertical:指定水平和垂直缩放时使用的滤波器类型。
space:指定输入和输出图像的颜色空间。

函数执行的步骤如下:

调用 stbir__resize_arbitrary 函数,提供了与输入图像和输出图像相关的参数,以及其他参数的默认值。
stbir__resize_arbitrary 函数将根据提供的参数执行图像的调整大小操作,并将结果存储在输出图像中。
返回调整大小操作的结果,即返回值表示操作是否成功

stbi_write_png

stbi_write_png 函数将图像数据保存为 PNG 格式,并写入到指定的文件中

STBIWDEF int stbi_write_png(char const *filename, int x, int y, int comp, const void *data, int stride_bytes)
{
   FILE *f;
   int len;
   unsigned char *png = stbi_write_png_to_mem((const unsigned char *) data, stride_bytes, x, y, comp, &len);
   if (png == NULL) return 0;

   f = stbiw__fopen(filename, "wb");
   if (!f) { STBIW_FREE(png); return 0; }
   fwrite(png, 1, len, f);
   fclose(f);
   STBIW_FREE(png);
   return 1;
}

filename:指定要保存的 PNG 文件的文件名。
x:图像的宽度(以像素为单位)。
y:图像的高度(以像素为单位)。
comp:图像的通道数。
data:指向图像数据的指针。
stride_bytes:图像每行的字节步长(即每行像素数据占用的字节数)

调用 stbi_write_png_to_mem 函数,将图像数据编码为 PNG 格式的内存块,并返回指向该内存块的指针。
检查返回的 PNG 内存块是否为 NULL,如果是则表示编码过程出错,返回 0 表示保存失败。
打开指定的文件以进行写入操作。
将 PNG 内存块的数据写入文件。
关闭文件。
释放 PNG 内存块的内存。
返回 1 表示保存成功。

将png图片缩小demo

#include <iostream>
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "stb_image_write.h"
#define STB_IMAGE_RESIZE_IMPLEMENTATION
#include "stb_image_resize.h"
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <vector>

using namespace std;

int test_xiao()
{
    std::cout << "Hello, STB_Image" << std::endl;

    string inputPath = "./001.png";
    int iw, ih, n;

    // 加载图片获取宽、高、颜色通道信息
    unsigned char *idata = stbi_load(inputPath.c_str(), &iw, &ih, &n, 0);

    int ow = iw / 2;
    int oh = ih / 2;
    auto *odata = (unsigned char *)malloc(ow * oh * n);

    // 改变图片尺寸
    stbir_resize(idata, iw, ih, 0, odata, ow, oh, 0, STBIR_TYPE_UINT8, n, STBIR_ALPHA_CHANNEL_NONE, 0,
                 STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP,
                 STBIR_FILTER_BOX, STBIR_FILTER_BOX,
                 STBIR_COLORSPACE_SRGB, nullptr);

    string outputPath = "./output.png";
    // 写入图片
    stbi_write_png(outputPath.c_str(), ow, oh, n, odata, 0);

    stbi_image_free(idata);
    stbi_image_free(odata);
    std::cout << "Voer, STB_Image" << std::endl;
    return 0;
}

图像基本知识学习

comp

comp:用于存储加载图像的颜色通道数(例如,RGB 图像为 3)的指针变量。 还有其他数字有不同的表示吗?

当加载的图像是 RGB 格式时,comp 将被设置为 3,表示有红色、绿色和蓝色三个通道。 当加载的图像是 RGBA 格式时,comp
将被设置为 4,表示有红色、绿色、蓝色和 Alpha 通道。

YUV420

YUV420是一种颜色编码格式,常用于存储和传输图像数据。它将图像的亮度(Y)和色度(U、V)分开存储,以实现数据压缩和降低存储/传输带宽的效果
YUV420的"420"指的是在水平和垂直方向上对色度(U、V)进行了抽样,即将色度通道的分辨率降低为亮度通道的四分之一。具体而言,对于每4个亮度像素,只有一个色度(U、V)样本被保留,这样可以大大减少存储和传输所需的数据量
在这里插入图片描述

RGB 数据存储格式

RGB24(RGB888):每个像素使用24位(3字节)存储,按照顺序存储红色、绿色和蓝色通道的像素值,每个通道占用8位。

RGB32(ARGB8888):每个像素使用32位(4字节)存储,按照顺序存储Alpha通道、红色通道、绿色通道和蓝色通道的像素值,每个通道占用8位。

RGB565:每个像素使用16位(2字节)存储,按照顺序存储红色、绿色和蓝色通道的像素值,其中红色通道占用5位,绿色通道占用6位,蓝色通道占用5位。

RGB444:每个像素使用12位(2字节)存储,按照顺序存储红色、绿色和蓝色通道的像素值,其中每个通道占用4位。

RGBA 数据格式

RGBA数据格式是一种将图像的红色(R)、绿色(G)、蓝色(B)和Alpha(A)通道的像素值以一定顺序存储的方法。与RGB数据格式相比,RGBA数据格式额外包含了Alpha通道,用于表示像素的透明度。

常见的RGBA数据存储格式包括:

RGBA32(ARGB8888):每个像素使用32位(4字节)存储,按照顺序存储Alpha通道、红色通道、绿色通道和蓝色通道的像素值,每个通道占用8位。

RGBA16(ARGB1555):每个像素使用16位(2字节)存储,按照顺序存储Alpha通道、红色通道、绿色通道和蓝色通道的像素值,其中Alpha通道占用1位,而红色、绿色和蓝色通道各占用5位。

RGBA4444:每个像素使用16位(2字节)存储,按照顺序存储Alpha通道、红色通道、绿色通道和蓝色通道的像素值,每个通道占用4位。

RGBA转YUV420 原理

颜色空间转换:首先将RGBA图像中的每个像素的颜色值转换为YUV颜色空间。这可以通过以下公式进行计算:
Y = 0.299 * R + 0.587 * G + 0.114 * B
U = (B - Y) * 0.565
V = (R - Y) * 0.713
这些公式将RGB颜色值转换为YUV颜色值,其中Y表示亮度,U和V表示色度。

采样:YUV420是一种色度子采样格式,意味着色度分量的采样率较低。具体来说,对于每个4x4的像素块,只有一个U和一个V值,而Y值则对应每个像素。

重排列:将Y、U和V分量的数据进行重排列,以满足YUV420的存储格式要求。对于每个4x4的像素块,先按照从左到右、从上到下的顺序排列Y值,然后按照从左到右、从上到下的顺序排列U和V值。这样可以保证Y、U和V分量的数据在存储时是连续的。

填充:由于YUV420是按照宏块(通常是16x16像素)为单位进行处理的,因此如果图像的宽度或高度不是宏块的倍数,就需要进行填充操作。填充通常是在图像边缘添加额外的像素值,使得宽度和高度能够被宏块大小整除。

RGB转YUV420 原理

颜色空间转换:首先,将RGB颜色空间的每个像素的颜色值转换为YUV颜色空间。这可以通过以下公式进行计算:
Y = 0.299 * R + 0.587 * G + 0.114 * B
U = (B - Y) * 0.564 + 128
V = (R - Y) * 0.713 + 128
这些公式将RGB颜色值转换为YUV颜色值,其中Y表示亮度,U和V表示色度。

采样和下采样:YUV420是一种色度子采样格式,意味着色度分量的采样率较低。对于每个4x4像素块,只有一个U值和一个V值,而Y值对应每个像素。

数据重排列:按照特定的规则,将Y、U和V分量的数据进行重排列以适应YUV420的存储格式要求。通常,对于每个4x4像素块,先将Y值按从左到右、从上到下的顺序排列,然后将U和V值按照特定的规则进行排列,以确保它们在存储时是连续的。

图像填充:由于YUV420是以宏块(通常是16x16像素)为单位进行处理的,因此如果图像的宽度或高度不是宏块的倍数,就需要进行填充操作。填充通常是在图像边缘添加额外的像素值,使得宽度和高度能够被宏块大小整除。

为什么RGB图像转换为YUV420格式

人类视觉特性:YUV420格式利用了人类视觉对亮度和色度的感知不均衡性。人眼对亮度的感知更为敏锐,而对色度的感知相对较弱。因此,在视频编码和传输中,将亮度和色度分开处理可以实现更高的压缩率,同时保持较好的视觉质量。

压缩效率:YUV420是一种色度子采样的格式,相对于RGB格式,它在色度分量上进行了下采样。在YUV420中,亮度分量(Y)的分辨率与原始图像相同,而色度分量(U和V)的分辨率较低。这种子采样可以大大减少数据量,从而实现更高的压缩效率。对于图像和视频的存储和传输,尤其是在带宽和存储资源有限的情况下,YUV420格式具有更高的效率。

兼容性:YUV420格式在广泛的视频编码和传输标准中被广泛使用,如H.264、H.265等。这些标准通常使用YUV420作为默认的输入格式,因此将RGB图像转换为YUV420可以方便地与这些标准进行集成和处理。

总结就是:更好的视觉效果,压缩后减少数据量,使用的场景更多

BMP图像

BMP(Bitmap)图像是一种常见的无损图像文件格式,它以像素阵列的形式存储图像数据。BMP图像最初由微软开发,是Windows操作系统中广泛使用的一种图像格式。以下是BMP图像的一些特点

无压缩格式:BMP图像使用无压缩的格式存储图像数据,即每个像素的颜色值都被直接存储,没有经过压缩算法的处理。这使得BMP图像保留了原始图像的每个像素的精确信息,不会有数据丢失。

色彩深度:BMP图像支持不同的色彩深度,包括1位、4位、8位、16位、24位和32位。其中,24位和32位的BMP图像是最常见的,它们分别使用RGB(红绿蓝)和RGBA(红绿蓝透明度)颜色模型来表示图像的每个像素。

文件结构:BMP图像文件由文件头和图像数据组成。文件头包含了一些元数据信息,如文件类型、文件大小、图像偏移等。图像数据部分存储了每个像素的颜色值。

支持透明通道:BMP图像可以支持透明通道,即RGBA格式的图像可以包含透明度信息,使得图像中的某些像素可以是部分透明的。

平台兼容性:BMP图像在多个平台上都有良好的兼容性,可以在Windows、Linux、Mac等操作系统上进行读取和显示

练习

RGBA转YUV420 YUV420转换为BMP图像

// YUV420转换为BMP图像
void yuv420_to_bmp_RGBA(uchar* yuv_data, int width, int height, const char* output_filename)
{
    int bmp_size = width * height * 3;
    uchar* bmp_data = (uchar*)malloc(bmp_size);

    int i, j;
    int bmp_idx = 0;
    int yuv_idx = 0;

    // Y分量
    for (i = 0; i < height; i++) {
        for (j = 0; j < width; j++) {
            bmp_data[bmp_idx++] = yuv_data[yuv_idx++];
        }
    }

    // U、V分量
    int uv_width = width / 2;
    int uv_height = height / 2;
    int uv_size = uv_width * uv_height;
    for (i = 0; i < uv_size; i++) {
        bmp_data[bmp_idx++] = yuv_data[yuv_idx++]; // U
        bmp_data[bmp_idx++] = yuv_data[yuv_idx++]; // V
    }

    // 写入BMP文件
    FILE* bmp_file = fopen(output_filename, "wb");
    if (bmp_file == NULL) {
        printf("Failed to open BMP file for writing\n");
        return;
    }

    // BMP文件头
    int file_size = bmp_size + 54; // BMP文件大小
    uchar bmp_header[54] = {
        'B', 'M', // 文件类型
        file_size & 0xFF, (file_size >> 8) & 0xFF, (file_size >> 16) & 0xFF, (file_size >> 24) & 0xFF, // 文件大小
        0, 0, 0, 0, // 保留
        54, 0, 0, 0, // 数据偏移量
        40, 0, 0, 0, // BITMAPINFOHEADER大小
        width & 0xFF, (width >> 8) & 0xFF, (width >> 16) & 0xFF, (width >> 24) & 0xFF, // 宽度
        height & 0xFF, (height >> 8) & 0xFF, (height >> 16) & 0xFF, (height >> 24) & 0xFF, // 高度
        1, 0, // 颜色平面数
        24, 0, // 位深度
        0, 0, 0, 0, // 无压缩
        0, 0, 0, 0, // 图像大小(可设置为0)
        0, 0, 0, 0, // 水平分辨率(可设置为0)
        0, 0, 0, 0, // 垂直分辨率(可设置为0)
        0, 0, 0, 0, // 调色板颜色数(可设置为0)
        0, 0, 0, 0  // 重要颜色数(可设置为0)
    };

    fwrite(bmp_header, sizeof(uchar), 54, bmp_file);
    fwrite(bmp_data, sizeof(uchar), bmp_size, bmp_file);

    fclose(bmp_file);
    free(bmp_data);

    printf("BMP image saved to %s\n", output_filename);
}

int IPG_YUV420_BMP_RGBA()
{
    const char* input_filename = "./002.jpg";
    const char* output_filename = "./002outputRGBA.bmp";

    int width, height, channels;
    uchar* image_data = stbi_load(input_filename, &width, &height, &channels, 0);
    if (image_data == NULL) {
        printf("Failed to load image: %s\n", input_filename);
        return 1;
    }

    if (channels != 4) {
        printf("Invalid image format: must be RGBA\n");
        stbi_image_free(image_data);
        return 1;
    }

    // 分配YUV420数据内存
    int yuv_size = width * height * 3 / 2;
    uchar* yuv_data = (uchar*)malloc(yuv_size);

    // RGBA转YUV420
    int i, j;
    int rgba_idx = 0;
    int y_idx = 0;
    int uv_idx = width * height;
    for (i = 0; i < height; i++) {
        for (j = 0; j < width; j++) {
            uchar r = image_data[rgba_idx++];
            uchar g = image_data[rgba_idx++];
            uchar b = image_data[rgba_idx++];
            uchar a = image_data[rgba_idx++];

            uchar y = (uchar)(0.299 * r + 0.587 * g + 0.114 * b);
            uchar u = (uchar)(-0.14713 * r - 0.28886 * g + 0.436 * b + 128);
            uchar v = (uchar)(0.615 * r - 0.51499 * g - 0.10001 * b + 128);

            yuv_data[y_idx++] = y;

            // 每隔一行和一列采样U、V分量
            if (i % 2 == 0 && j % 2 == 0) {
                yuv_data[uv_idx++] = u;
                yuv_data[uv_idx++] = v;
            }
        }
    }

    // 将YUV420转换为BMP图像
    yuv420_to_bmp_RGBA(yuv_data, width, height, output_filename);

    stbi_image_free(image_data);
    free(yuv_data);

    return 0;
}

RGB 转YUV420 YUV420转换为BMP图像


```c
typedef unsigned char uchar;

// YUV420转换为BMP图像
void yuv420_to_bmp(uchar *yuv_data, int width, int height, const char *output_filename)
{
    int bmp_size = width * height * 3;
    uchar *bmp_data = (uchar *)malloc(bmp_size);

    int i, j;
    int bmp_idx = 0;
    int yuv_idx = 0;

    // Y分量
    for (i = 0; i < height; i++)
    {
        for (j = 0; j < width; j++)
        {
            bmp_data[bmp_idx++] = yuv_data[yuv_idx++];
        }
    }

    // U、V分量
    int uv_width = width / 2;
    int uv_height = height / 2;
    int uv_size = uv_width * uv_height;
    for (i = 0; i < uv_size; i++)
    {
        bmp_data[bmp_idx++] = yuv_data[yuv_idx++]; // U
        bmp_data[bmp_idx++] = yuv_data[yuv_idx++]; // V
    }

    // 写入BMP文件
    FILE *bmp_file = fopen(output_filename, "wb");
    if (bmp_file == NULL)
    {
        printf("Failed to open BMP file for writing\n");
        return;
    }

    // BMP文件头
    int file_size = bmp_size + 54; // BMP文件大小
    uchar bmp_header[54] = {
        'B', 'M',                                                                                      // 文件类型
        file_size & 0xFF, (file_size >> 8) & 0xFF, (file_size >> 16) & 0xFF, (file_size >> 24) & 0xFF, // 文件大小
        0, 0, 0, 0,                                                                                    // 保留
        54, 0, 0, 0,                                                                                   // 数据偏移量
        40, 0, 0, 0,                                                                                   // BITMAPINFOHEADER大小
        width & 0xFF, (width >> 8) & 0xFF, (width >> 16) & 0xFF, (width >> 24) & 0xFF,                 // 宽度
        height & 0xFF, (height >> 8) & 0xFF, (height >> 16) & 0xFF, (height >> 24) & 0xFF,             // 高度
        1, 0,                                                                                          // 颜色平面数
        24, 0,                                                                                         // 位深度
        0, 0, 0, 0,                                                                                    // 无压缩
        0, 0, 0, 0,                                                                                    // 图像大小(可设置为0)
        0, 0, 0, 0,                                                                                    // 水平分辨率(可设置为0)
        0, 0, 0, 0,                                                                                    // 垂直分辨率(可设置为0)
        0, 0, 0, 0,                                                                                    // 调色板颜色数(可设置为0)
        0, 0, 0, 0                                                                                     // 重要颜色数(可设置为0)
    };

    fwrite(bmp_header, sizeof(uchar), 54, bmp_file);
    fwrite(bmp_data, sizeof(uchar), bmp_size, bmp_file);

    fclose(bmp_file);
    free(bmp_data);

    printf("BMP image saved to %s\n", output_filename);
}
/*
基于stbimg开源库实现jpg解码为YUV420,YUV420转换为BMP图片工程
*/
int IPG_YUV420_BMP()
{
    const char *input_filename = "./002.jpg";
    const char *output_filename = "./002output.bmp";

    int width, height, channels;
    uchar *image_data = stbi_load(input_filename, &width, &height, &channels, 0);
    if (image_data == NULL)
    {
        printf("Failed to load image: %s\n", input_filename);
        return 1;
    }
    // return 0;
    printf("%s %d channels = %d\n", __func__, __LINE__, channels);
    if (channels != 3)
    {
        printf("Invalid image format: must be RGB\n");
        stbi_image_free(image_data);
        return 1;
    }

    // 分配YUV420数据内存
    int yuv_size = width * height * 3 / 2;
    uchar *yuv_data = (uchar *)malloc(yuv_size);

    // RGB转YUV420
    int i, j;
    int rgb_idx = 0;
    int y_idx = 0;
    int uv_idx = width * height;
    for (i = 0; i < height; i++)
    {
        for (j = 0; j < width; j++)
        {
            uchar r = image_data[rgb_idx++];
            uchar g = image_data[rgb_idx++];
            uchar b = image_data[rgb_idx++];

            uchar y = (uchar)(0.299 * r + 0.587 * g + 0.114 * b);
            uchar u = (uchar)(-0.14713 * r - 0.28886 * g + 0.436 * b + 128);
            uchar v = (uchar)(0.615 * r - 0.51499 * g - 0.10001 * b + 128);

            yuv_data[y_idx++] = y;

            // 每隔一行和一列采样U、V分量
            if (i % 2 == 0 && j % 2 == 0)
            {
                yuv_data[uv_idx++] = u;
                yuv_data[uv_idx++] = v;
            }
        }
    }

    // 将YUV420转换为BMP图像
    yuv420_to_bmp(yuv_data, width, height, output_filename);

    stbi_image_free(image_data);
    free(yuv_data);

    return 0;
}



参考:
[https://mp.weixin.qq.com/s/Mh_cLQeRy5J5AufeaGaOmA](https://mp.weixin.qq.com/s/Mh_cLQeRy5J5AufeaGaOmA)
[https://blog.csdn.net/www_dong/article/details/115149370](https://blog.csdn.net/www_dong/article/details/115149370)


注意:如果代码运行有问题,慢慢检查,仔细看一下错误是什么!

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

字符函数和字符串函数上篇(详解)

❤️ 作者简介 &#xff1a;RO-BERRY 致力于C、C、数据结构、TCP/IP、数据库等等一系列知识&#xff0c;对纯音乐有独特的喜爱 &#x1f4d7; 日后方向 : 偏向于CPP开发以及大数据方向&#xff0c;如果你也感兴趣的话欢迎关注博主&#xff0c;期待更新 字符函数和字符串函数 &a…

详解GPT技术发展脉络

文章目录 前言关于本篇的分享内容大语言模型大模型语言模型 百花齐放TransformerAuto-RegressiveResnetLayer-NormMaskScaled Dot-Product AttentionMulti-Head AttenionSelf-AttentionPositional Encoding关于并行计算关于长程依赖Transformer演化 GPT SeriesGPT-1GPT-2GPT-3 …

unity 2019 内置渲染管线 光照与Lighting面板 参数详解

文章目录 前言一 Unity的光照 与 烘焙光照1 unity完整的光照组成2 光的亮度与颜色3 全局光照直接光间接光5 间接光≠光照贴图 二 色彩空间与自动烘焙1 unity的色彩空间2 自动烘焙光照 三 烘焙1 什么是烘焙&#xff0c;烘焙的是什么2 如何进行烘焙3 烘焙的优点和缺点4 查看光照贴…

相交链表——力扣160

题目描述 法一&#xff09;哈希表 class Solution{ public:ListNode* getIntersectionNode (ListNode* headA, ListNode* headB){unordered_set<ListNode*> st;ListNode* temp headA;while(temp){st.insert(temp);temp temp->next;}temp headB;while(temp){if(st.c…

python+allure+jenkins

目录 前言 在 python 中使用 allure 1. 安装 pytest 2. 安装 pytest-allure-adaptor 3. 使用 pytest 执行测试用例并生成 allure 中间报告&#xff08;此步骤可以省略&#xff0c;因为在 jenkins job 中会配置执行类似的命令&#xff09; 4. Jenkins 中安装Allure Jenkin…

《生活教育》期刊简介及投稿邮箱

《生活教育》期刊简介及投稿邮箱 《生活教育》杂志创办于1934&#xff0c;是中华人民共和国教育部主管的国家重点学术期刊&#xff0c;国家级期刊&#xff0c;中国知网全文收录G4期刊&#xff0c;它的理论是陶行知教育思想的主线和重要基石&#xff0c;陶行知的教育理论&#…

【C#】并行编程实战:使用延迟初始化提高性能

在前面的章节中讨论了 C# 中线程安全并发集合&#xff0c;有助于提高代码性能、降低同步开销。本章将讨论更多有助于提高性能的概念&#xff0c;包括使用自定义实现的内置构造。 毕竟&#xff0c;对于多线程编程来讲&#xff0c;最核心的需求就是为了性能。 延迟初始化 - .NET…

C#安装.Net平台科学计算库Math.Net Numerics

工作的时候需要使用到C#的Math.Net库来进行计算。 Math.Net库涵盖的主题包括特殊函数&#xff0c;线性代数&#xff0c;概率模型&#xff0c;随机数&#xff0c;插值&#xff0c;积分&#xff0c;回归&#xff0c;优化问题等。 这里记录一下&#xff0c;安装Math.Net库的过程…

el-date-picker组件的picker-options常规属性设置

查询已发生的配置项 // 日期选择器快捷键配置&#xff08;一般过去时&#xff09; pickerOptions: {shortcuts: [{text: 今天,onClick(picker) {let start new Date();let end new Date();picker.$emit(pick, [start, end]);}},{text: 昨天,onClick(picker) {let start new…

uniapp微信小程序使用axios(vue3+axios+ts版)

版本号 "vue": "^3.2.45", "axios": "^1.4.0", "axios-miniprogram-adapter": "^0.3.5", 安装axios及axios适配器&#xff0c;适配小程序 yarn add axios axios-miniprogram-adapter 使用axios 在utils创建utils/…

Flask SQLAlchemy_Serializer ORM模型序列化

在前后端分离项目中&#xff0c;经常需要把ORM模型转化为字典&#xff0c;再将字典转化为JSON格式的字符串。在遇到sqlalchemy_serializer之前&#xff0c;我都是通过类似Java中的反射原理&#xff0c;获取当前ORM模型的所有字段&#xff0c;然后写一个to_dict方法来将字段以及…

计算机vcruntime140.dll丢失的解决方法,重新安装教程

vcruntime140.dll是Microsoft Visual C Redistributable文件中的一个动态链接库&#xff08;DLL&#xff09;。这个文件是由Microsoft开发的&#xff0c;用于支持C编程语言的运行环境。vcruntime140.dll是Windows系统非常重要的文件&#xff0c;通常会被一些应用程序或游戏所需…

Jenkins | 获取凭证密码

目录 方法一&#xff1a;查看所有账号及密码 方法二&#xff1a;查看指定账号密码 方法一&#xff1a;查看所有账号及密码 Jenkins > 系统管理 > 脚本命令行 com.cloudbees.plugins.credentials.SystemCredentialsProvider.getInstance().getCredentials().forEach{i…

Linux进程

Linux进程 对于进程的理解&#xff0c;我们要从计算机的重要的冯诺依曼体系结构讲起&#xff0c;只有知道我们的程序/文件是如何在计算机中被操作运行并输出到显示器中&#xff0c;通过对于操作系统的理解&#xff0c;才能对于进程进行一定的理解。 文章目录 Linux进程冯诺依…

【Linux】udp服务器实现大型网络聊天室

udp终结篇~ 文章目录 前言一、udp服务器实现大型网络聊天室总结 前言 根据上一篇文章中对于英汉互译和远程操作的两个小功能大家应该已经学会了&#xff0c;我们的目的是让大家可以深刻的理解udp服务器所需要的接口已经实现的简单步骤&#xff0c;下面我们开始实现网络聊天室。…

3.SpringBoot 返回Html界面

1.添加依赖spring-boot-starter-web <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency>2.创建Html界面 在Resources/static 文件夹下面建立对应的html&#xff0c…

快速排序的非递归实现、归并排序的递归和非递归实现、基数排序、排序算法的时间复杂度

文章目录 快速排序的非递归三数取中法选取key快速排序三路划分 归并排序的递归归并排序的非递归计数排序稳定性排序算法的时间复杂度 快速排序的非递归 我们使用一个栈来模拟函数的递归过程&#xff0c;这里就是在利用栈分区间。把一个区间分为 [left,keyi-1][key][keyi1,right…

用百度地图api获取当前定位,获取经纬度——前端笔记

问题&#xff1a; 做一个按钮&#xff0c;点击后可以获取到当前位置的经纬度&#xff0c;并渲染地图。 效果如下: 代码如下: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head><title>获取当前定位测试<…

【笔记MD】

https://editor.csdn.net/md/?not_checkout1&articleId131798584 这里写自定义目录标题 https://editor.csdn.net/md/?not_checkout1&articleId131798584欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题&#xff0c;有助于目录的生成如何改变文本的样式插入…

行业数据和报告到底应该如何去找?

信息时代&#xff0c;经常要对行业信息进行分析。这时首先就是要进行信息收集和筛选&#xff0c;如果我们懂得构建自己的工作工具和数据来源&#xff0c;效率会蹭蹭往上涨。 找行业报告、了解行业趋势&#xff0c;提高效率。 1. 国家权威 国家统计局&#xff1a;这个网站覆盖…