✺ch5——纹理贴图

news2024/11/25 10:55:12

目录

    • 加载纹理图像文件
    • 纹理坐标
    • 在着色器中使用纹理:采样器变量和纹理单元
    • 纹理贴图:示例程序
    • 多级渐远纹理贴图
    • 各向异性过滤
    • 环绕和平铺
    • 透视变形
    • 材质——更多OpenGL细节
    • 补充说明

纹理贴图是在栅格化的模型表面上覆盖图像的技术。 它是为渲染场景添加真实感的最基本和最重要的方法之一。

纹理贴图非常重要,因此硬件也为它提供了支持,使得它具备实现实时的照片级真实感的超高性能。纹理单元是专为纹理设计的硬件组件,现代显卡通常带有数个纹理单元。

加载纹理图像文件

为了在 OpenGL/GLSL 中有效地完成纹理贴图,需要协调好以下几个不同的数据集和机制:

  • 用于保存纹理图像的纹理对象(在本章中我们仅考虑 2D 图像);
  • 特殊的统一采样器变量,以便顶点着色器访问纹理;
  • 用于保存纹理坐标的缓冲区;
  • 用于将纹理坐标传递给管线的顶点属性;
  • 显卡上的纹理单元。

图像通常存储在图像文件中,例如.jpg、.png、.gif 或.tiff 文件。为了使纹理图像用于 OpenGL 管线中的着色器, 我们需要从图像中提取颜色并将它们放入 OpenGL 纹理对象(用于保存纹理图像的内置 OpenGL 结构)中。

许多 C++ 库可用于读取和处理图像文件,常见的选择包括 Cimg 、 BoostGIL 和 Magick++。我们选择使用专为 OpenGL 设计的 SOIL2 库。

通常,将纹理加载到 OpenGL 应用程序的步骤是:
(a)使用 SOIL2 实例化 OpenGL 纹理对象并从图像文件中读入数据;
(b)调用 glBindTexture() 以使新创建的纹理对象处于激活状态;
(c)使用 glTexParameter() 函数调整纹理设置。
最终得到的结果就是现在可用的 OpenGL 纹理对象的整型 ID。

GLuint loadTexture(const char* texImagePath) {
	GLuint textureID;
	textureID = SOIL_load_OGL_texture(texImagePath, SOIL_LOAD_AUTO, SOIL_CREATE_NEW_ID, SOIL_FLAG_INVERT_Y);
	if (textureID == 0)
		cout << "Could not find texture file:" << texImagePath << endl;
	return textureID;
}

纹理坐标

现在我们已经有了将纹理图像加载到 OpenGL 中的方法, 需要指定希望如何将纹理应用于对象的渲染表面。我们通过为模型中的每个顶点指定纹理坐标来完成此操作。

纹理坐标是对纹理图像(通常是 2D 图像)中的像素的引用。纹理图像中的像素被称为纹元(texel),以便将它们与在屏幕上呈现的像素区分开。纹理坐标用于将 3D 模型上的点映射到纹理中的位置。除了将它定位在 3D 空间中的坐标(x,y,z)之外,模型表面上的每个点还具有纹理坐标(s,t), 用来指定纹理图像中的哪个纹元为它提供颜色。 因此,我们将设置两个缓冲区,一个用于顶点坐标(每个条目中有 3 个分量,即 x、 y 和 z),另一个用于相应的纹理坐标(每个条目中有两个分量,即 s 和 t)。这样,每次顶点着色器的调用会接收到一个顶点的数据,包括其空间坐标和相应的纹理坐标。

2D 纹理图像被设定为矩形,左下角的位置坐标为(0,0),右上角的位置坐标为(1,1)。理想情况下,纹理坐标应该在[0, 1]区间内取值。

纹理坐标(由 s 和 t 描述)将图像的部分(纹元)映射到模型正面的栅格化像素上。顶点之间的所有中间像素都已使用图像中间插值的纹元进行绘制。这正是因为纹理坐标在顶点属性中被发送到片段着色器,从而也像顶点本身一样被插值。

下面我们渲染四棱锥,只是这次用砖的图像添加纹理。我们需要指定:
(a)引用纹理图像的整型 ID;
(b)模型顶点的纹理坐标;
(c)用于保存纹理坐标的缓冲区;
(d)顶点属性,以便顶点着色器接收并通过管线转发纹理坐标;
(e)显卡上用于保存纹理对象的纹理单元;
(f)用于访问 GLSL 中纹理单元的统一采样器变量。

在着色器中使用纹理:采样器变量和纹理单元

为了最大限度地提高性能,我们希望在硬件中执行纹理处理。这意味着片段着色器需要一种访问我们在 C++/OpenGL 应用程序中创建的纹理对象的方法。它的实现机制是通过一个叫作统一采样器变量的特殊 GLSL 工具。这是一个变量,用于指示显卡上的纹理单元,从加载的纹理对象中提取或“采样”纹元。

layout(binding = 0) uniform sampler2D samp;

我们声明的变量叫作 samp。声明的 layout(binding=0)部分指定此采样器与第 0 个纹理单元关联。

纹理单元(和相关的采样器)可以对我们希望的任何纹理对象进行采样,也可以在运行时更改。 display()函数需要指定纹理单元要为当前帧采样的纹理对象。因此,每次绘制对象时,都需要激活纹理单元并将其绑定到特定的纹理对象,例如:

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, brickTexture);

可用纹理单元的数量取决于显卡提供的数量。根据 OpenGL API 文档, OpenGL 4.5 要求每个着色器阶段至少有 16 个单元,所有阶段总共至少有 80 个单元。在这个例子中,我们通过在 glActiveTexture() 调用中指定 GL_TEXTURE0,使得第 0 个纹理单元处于激活状态。

要实际执行纹理处理,我们需要修改片段着色器输出颜色的方式。以前,我们的片段着色器要么输出一个固定的颜色常量,要么从顶点属性获取颜色,而这次我们需要使用从顶点着色器(通过光栅着色器)接收的插值纹理坐标来对纹理对象进行采样。调用 texture()函数如下:

in vec2 tc;// 输入插值过的纹理坐标
...
color = texture(samp, tc);

纹理贴图:示例程序

...
GLuint brickTexture;

void setupVertices(void) {
	float pyramidPositions[54] =
	{ -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 0.0f, 1.0f, 0.0f,    //front
		1.0f, -1.0f, 1.0f, 1.0f, -1.0f, -1.0f, 0.0f, 1.0f, 0.0f,    //right
		1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, 0.0f, 1.0f, 0.0f,  //back
		-1.0f, -1.0f, -1.0f, -1.0f, -1.0f, 1.0f, 0.0f, 1.0f, 0.0f,  //left
		-1.0f, -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, //LF
		1.0f, -1.0f, 1.0f, -1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f  //RR
	};
	float textureCoordinates[36] =
	{ 0.0f, 0.0f, 1.0f, 0.0f, 0.5f, 1.0f,
		0.0f, 0.0f, 1.0f, 0.0f, 0.5f, 1.0f,
		0.0f, 0.0f, 1.0f, 0.0f, 0.5f, 1.0f,
		0.0f, 0.0f, 1.0f, 0.0f, 0.5f, 1.0f,
		0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f,
		1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f
	};
	glGenVertexArrays(1, vao);
	glBindVertexArray(vao[0]);
	glGenBuffers(numVBOs, vbo);

	glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
	glBufferData(GL_ARRAY_BUFFER, sizeof(pyramidPositions), pyramidPositions, GL_STATIC_DRAW);

	glBindBuffer(GL_ARRAY_BUFFER, vbo[1]);
	glBufferData(GL_ARRAY_BUFFER, sizeof(textureCoordinates), textureCoordinates, GL_STATIC_DRAW);
}

void init(GLFWwindow* window) {
	...
	brickTexture = Utils::loadTexture("brick1.jpg");
}

void display(GLFWwindow* window, double currentTime) {
	glClear(GL_DEPTH_BUFFER_BIT);
	glClearColor(0.0, 0.0, 0.0, 1.0);
	glClear(GL_COLOR_BUFFER_BIT);

	glUseProgram(renderingProgram);

	mvLoc = glGetUniformLocation(renderingProgram, "mv_matrix");
	projLoc = glGetUniformLocation(renderingProgram, "proj_matrix");

	vMat = glm::translate(glm::mat4(1.0f), glm::vec3(-cameraX, -cameraY, -cameraZ));

	mMat = glm::translate(glm::mat4(1.0f), glm::vec3(pyrLocX, pyrLocY, pyrLocZ));

	mMat = glm::rotate(mMat, -0.45f, glm::vec3(1.0f, 0.0f, 0.0f));
	mMat = glm::rotate(mMat,  0.61f, glm::vec3(0.0f, 1.0f, 0.0f));
	mMat = glm::rotate(mMat,  0.00f, glm::vec3(0.0f, 0.0f, 1.0f));

	mvMat = vMat * mMat;

	glUniformMatrix4fv(mvLoc, 1, GL_FALSE, glm::value_ptr(mvMat));
	glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(pMat));

	glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
	glEnableVertexAttribArray(0);

	glBindBuffer(GL_ARRAY_BUFFER, vbo[1]);
	glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, 0);
	glEnableVertexAttribArray(1);

	glActiveTexture(GL_TEXTURE0);
	glBindTexture(GL_TEXTURE_2D, brickTexture);

	glEnable(GL_DEPTH_TEST);
	glDepthFunc(GL_LEQUAL);

	glDrawArrays(GL_TRIANGLES, 0, 18);
}

顶点着色器:

#version 430

layout (location=0) in vec3 pos;
layout (location=1) in vec2 texCoord;
out vec2 tc;

uniform mat4 mv_matrix;
uniform mat4 proj_matrix;
layout (binding=0) uniform sampler2D samp;

void main(void) {
	gl_Position = proj_matrix * mv_matrix * vec4(pos,1.0);
	tc = texCoord;
} 

片段着色器:

#version 430

in vec2 tc;
out vec4 color;

layout(binding = 0) uniform sampler2D samp;

void main(void) {
	color = texture(samp, tc);
}

多级渐远纹理贴图




多级渐远纹理贴图通过一种巧妙的机制来工作, 它在纹理图像中存储相同图像的连续的一系列较低分辨率的副本,所用的纹理图像比原始图像大 1/3,其中图像的 RGB 值分别存储在纹理图像空间的 3 个 1/4 区域中来实现的。剩余的 1/4 区域中迭代地将图像分辨率设置为原来的 1/4,直到剩余区域太小而不包含任何有用的图像数据。示例图像和生成的多级渐远纹理的可视化如下图所示。

这种将几个图像填充到一个小空间中的方法(只比存储原始图像所需的空间大一点)是 mipmapping 得名的原因。 mip 代表拉丁语 multumin parvo,意思是“在很小的空间里有很多东西”。

实际给对象添加纹理时,可以通过多种方法对多级渐远纹理进行采样。在 OpenGL 中,可以通过将 GL_TEXTURE_MIN_FILTER 参数设置为所需的缩小方法来选择多级渐远纹理的采样方法,可以选取以下方法之一:

  • GL_NEAREST_MIPMAP_NEAREST:选择具有与纹元区域最相似的分辨率的多级渐远纹理。然后,它获得所需纹理坐标的最近纹元。
  • GL_LINEAR_MIPMAP_NEAREST:选择具有与纹元区域最相似的分辨率的多级渐远纹理。然后,它取最接近纹理坐标的 4 个纹元的插值。这被称为“线性过滤”。
  • GL_NEAREST_MIPMAP_LINEAR:选择具有与纹元区域最相似的分辨率的 2 个多级渐远纹理。然后,它从每个多级渐远纹理获取纹理坐标的最近纹元并对其进行插值。这被称为“双线性过滤”。
  • GL_LINEAR_MIPMAP_LINEAR: 选择具有与纹元区域最相似的分辨率的 2 个多级渐远纹理。然后,它取各自最接近纹理坐标的 4 个纹元,并计算插值。这被称为“三线性过滤”。

三线性过滤通常是比较好的选择,因为较低的混合级别通常会产生伪影。

OpenGL 提供了丰富的多级渐远纹理支持,其中一些机制可用于构建你自己的多级渐远纹理级别,另一些机制可以让 OpenGL 为你构建它们。在大多数情况下, OpenGL 自动构建的多级渐远纹理已足够。这是通过将以下代码行添加进紧跟 getTextureObject()函数的 Utils::loadTexture()函数来实现的:

glBindTexture(GL_TEXTURE_2D, textureID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glGenerateMipmap(GL_TEXTURE_2D);

上述代码用于通知 OpenGL 生成多级渐远纹理。 glBindTexture()调用激活砖纹理,然后glTexParameteri()函数调用启用前面列出的缩小方法之一,此处为 GL_LINEAR_ MIPMAP_LINEAR,即三线性过滤。

构建多级渐远纹理后,可以在 display()函数中或其他位置再次调用 glTexParameteri()来更改过滤选项(尽管很少有需要这样做的情况),甚至通过选择 GL_NEAREST 或 GL_LINEAR 来禁用多级渐远纹理。

各向异性过滤

多级渐远纹理贴图有时看起来比非多级渐远纹理贴图更模糊, 尤其是当被贴图对象以严重倾斜的视角渲染时。使用多级渐远纹理贴图在减少伪影的同时也损失了图像细节。

这种细节的丢失是因为当物体倾斜时,其图元看起来在一个轴(即沿宽或高)上的尺寸比在另一个轴上更小。当 OpenGL 为图元贴图时,它选择适合两个轴中尺寸较小的轴的多级渐远纹理(以避免“闪烁”伪影)。表面远离观察者倾斜,因此每个渲染图元将使用适合其更小尺寸(即高度)的多级渐远纹理,对其宽度来说,这个分辨率似乎太小了。

一种恢复一些丢失细节的方法是使用各向异性过滤(Anisotropic Filtering,AF)。标准的多级渐远纹理贴图以各种正方形分辨率(如 256 像素×256 像素、 128 像素×128 像素等)对纹理图像进行采样,而各向异性过滤却以多种矩形分辨率对纹理进行采样(如 256 像素×128 像素、 64 像素×128 像素等)。这使得从各种角度观看的纹理都保留尽可能多的细节成为可能。

各向异性过滤比标准多级渐远纹理贴图的计算代价更高,并且不是 OpenGL 的必需部分。但是,大多数显卡都支持各向异性过滤(称为 OpenGL 扩展),而 OpenGL 也确实提供了一种查询显卡是否支持各向异性过滤的方法,以及一种访问各向异性过滤的方法,只需在生成多级渐远纹理贴图后立即添加代码:

...
// 如果使用多级渐远纹理贴图
glBindTexture(GL_TEXTURE_2D, textureID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glGenerateMipmap(GL_TEXTURE_2D);
// 如果还使用各向异性过滤
if (glewIsSupported("GL_EXT_texture_filter_anisotropic")) {
	GLfloat anisoSetting = 0.0f;
	glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &anisoSetting);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, anisoSetting);
}

对 glewIsSupported()进行调用可以测试显卡是否支持各向异性过滤。如果支持,我们将其设置为支持的最
大采样程度,这个最大值通过 glGetFloatv()获取。使用glTexParameterf()可以将其应用于激活纹理对象,结果如下图所示。请注意,丢失的大部分细节已经恢复,同时我们仍然消除了闪烁的伪影。

环绕和平铺

到目前为止,我们假设纹理坐标都落在[0, 1]区间。但是, OpenGL 实际上支持任何取值范围的纹理坐标。有几个选项可以用来指定当纹理坐标超出[0, 1]区间时会发生什么,可以使用glTexParameteri()设置。这些选项如下:

  • GL_REPEAT:重复,即忽略纹理坐标的整数部分,生成重复或“平铺”图案。这是默认行为。
  • GL_MIRRORED_REPEAT:镜像重复,即忽略纹理坐标的整数部分,但是当整数部分为奇数时反转坐标,因此重复的图案在原图案和其镜像图案之间交替。
  • GL_CLAMP_TO_EDGE: 夹紧到边缘, 即将小于 0 的坐标和大于 1 的坐标分别设置为 0 和 1。
  • GL_CLAMP_TO_BORDER: 夹紧到边框, 即将[0, 1]以外的纹元设置成指定的边框颜色。

例如,考虑一个使用图 5.2 中纹理图像的四棱锥,其纹理坐标区间已达[0, 5],而不是通常
的[0, 1]。默认行为(即 GL_REPEAT)会导致纹理在表面上重复(有时称为“平铺”),如图 5.17
所示。

为了使平铺块的外观在原图案和其镜像之间交替,我们可以指定以下内容:

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);

可以按如下方式来将小于 0 或大于 1 的值设定为指定颜色:

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
float redColor[4] = { 1.0f, 0.0f, 0.0f, 1.0f };
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, redColor);

下图中分别(从左到右)显示了重复、镜像重复、夹紧到边缘和夹紧到边框的效果,其中四棱锥的纹理坐标取值范围为−2~+3:

透视变形

考虑一个由两个三角形组成的矩形,纹理贴图是棋盘图样,面向相机。当矩形围绕 x 轴旋转时,矩形的顶部会倾斜并远离相机,而矩形的下半部分则更靠近相机。因此,我们希望顶部的方块变小,底部的方块变大。但是,纹理坐标的线性插值将导致所有正方形的高度相等。沿着构成矩形的两个三角形接缝处的对角线加剧失真。产生的失真如下图所示。

幸运的是,存在用于校正透视失真的算法,并且默认情况下, OpenGL 在栅格化期间会应用透视校正算法。

可以通过在包含纹理坐标的顶点属性的声明中添加关键字“noperspective”来禁用 OpenGL 的透视校正,虽然这样做并不常见。顶点着色器和片段着色器中都需要这样添加关键字。例如,顶点着色器中的顶点属性将声明如下:

noperspective out vec2 texCoord;

片段着色器中的相应属性声明为:

noperspective in vec2 texCoord;

实际上,上图中的扭曲的棋盘图样就使用了这种语法来生成图的。

材质——更多OpenGL细节

我们使用的 SOIL2 纹理图像加载库具有相对简单和直观的优点。但是,在学习 OpenGL 时,使用 SOIL2 会产生一项我们不想要的后果,即用户会接触不到一些有用的重要OpenGL 细节。在本节中,我们将描述程序员在没有纹理加载库(如 SOIL2)的情况下加载和使用纹理时需要了解的一些细节。

可以使用 C++和 OpenGL 函数直接将纹理图像文件数据加载到 OpenGL 中。这虽然有点儿复杂,但并不少见。一般步骤如下:
(1)使用 C++ 工具读取图像文件数据;
(2)生成 OpenGL 纹理对象;
(3)将图像文件数据复制到纹理对象中。

我们不会详细描述第一步——有太多方法了。 opengl-tutorials 网站中很好地描述了一种方法,可以使用 C++函数 fopen()和 fread()将数据从.bmp 图像文件读入 unsigned char 类型的数组。

步骤(2)和步骤(3)更通用,主要涉及 OpenGL 调用。在步骤(2)中,我们使用 OpenGL 的glGenTextures()命令创建一个或多个纹理对象。例如,生成单个 OpenGL 纹理对象(使用整型引用 ID)可以按如下方式完成:

GLuint textureID;// 如果需要创建多于一个纹理对象,则使用 GLuint 类型的数组
glGenTextures(1, &textureID);

在步骤(3)中,我们将步骤(1)中的图像文件数据关联到步骤(2)中创建的纹理对象。这是使用 OpenGL 的 glTexImage2D()命令完成的。下面的示例将图像文件数据从步骤(1)中描述的 unsigned char 类型的数组(此处表示为 data)加载到步骤(2)创建的纹理对象中:

glBindTexture(GL_TEXTURE_2D, textureID)
glTexImage2D(GL_TEXTURE_2D, 0,GL_RGB, width, height, 0, GL_BGR, GL_UNSIGNED_BYTE, data);

此时,本章前面介绍的用于设置多级渐远纹理贴图等的各种 glTexParameteri()调用也可以应用于纹理对象。

补充说明

研究人员开发了纹理单元的许多用途,不仅仅用于场景中的纹理模型。在后面的章节中,我们将看到如何使用纹理单元来改变物体反射光线,使其看起来凹凸不平。我们还可以使用纹理单元来存储“高度图”以生成地形,以及存储“阴影贴图”以有效地为场景添加阴影。

着色器还可以向纹理写入数据,允许着色器修改纹理图像,甚至将一个纹理的一部分复制到另一个纹理的某个部分。

多级渐远纹理贴图和各向异性过滤不是减少纹理中的叠影、伪影的唯一工具。例如,全屏抗锯齿( Full-Scene Anti-Aliasing, FSAA)和其他超采样方法也可以改善 3D 场景中纹理的外观。它们虽然不是 OpenGL 核心的一部分,但通过 OpenGL 的扩展机制在许多显卡上得到了支持。

还有一种用于配置和管理纹理和采样器的替代机制。 OpenGL 3.3 引入了采样器对象(有时称为“采样器状态”,不要与采样器变量混淆),可用于保存一组独立于实际纹理对象的纹理设置。将采样器对象附加到纹理单元,可以方便、 有效地更改纹理设置。

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

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

相关文章

Python三级 每周练习题31

如果你感觉有收获&#xff0c;欢迎给我微信扫打赏码 ———— 以激励我输出更多优质内容 练习一: 作业1:编写程序&#xff0c;在下面的字典中找出身高137的同学并输出姓名&#xff0c;如果没找到&#xff0c; 输出没有 a{‘小赵’:136,‘小钱’:141,‘小孙’:146,‘小李’:13…

操作系统基础知识

本文用于记录学习W3schools的操作系统教程&#xff0c;该教程的部分内容比较难懂&#xff0c;所以也参考了其他文章。 操作系统基础知识 一、操作系统概括二、操作系统的8个组件1 流程管理2 I/O设备管理3 文件管理4 网络管理5 内存管理6 磁盘管理(辅助存储管理)7 安全管理8 命令…

Elasticsearch——快速入门

从零基础的内容开始介绍Elasticsearch&#xff0c;主要包含以下内容&#xff1a; Elasticsearch的定义、优点&#xff0c;以及典型的业务场景。Elasticsearch中重要的概念。Elasticsearch典型的接入方式。安装Elasticsearch。使用Kibana调试Elasticsearch。Elasticsearch节点的…

【Transformer】ViT and TNT(2)

文章目录 VITTNT 太…完整了&#xff01;同济大佬唐宇迪博士终于把【Transformer】入门到精通全套课程分享出来了&#xff0c;最新前沿方向 学习笔记 VIT eg&#xff0c;图片分块&#xff0c;10x10x3 的 patch 通过 conv 拉成向量&#xff0c;就无缝对接了 位置编码可以多种方…

硬件基础:光耦、可控硅、继电器、达林顿管、干簧管

光耦 光电耦合器&#xff08;optical coupler&#xff0c;英文缩写为OC&#xff09;亦称光电隔离器&#xff0c;简称光耦。 光电耦合器是一种把发光器件和光敏器件封装在同一壳体内&#xff0c; 中间通过电→光→电的转换来传输电信号的半导体光电子器件。其中&#xff0c;发光…

三勾商城新功能-电子面单发货

商家快递发货时可以选择在线下单,在线获取和打印电子面单。免去手写面单信息以及避免填写运单号填错,系统会自动填写对应发货商品的运单信息 快递100电子面单1、进入快递100&#xff0c;点击登录 2、登录成功后&#xff0c;点击“电子面单与云打印” 3、进入电子面单与云打印后…

什么是缓存击穿、缓存穿透、缓存雪崩?

&#x1f680; 作者主页&#xff1a; 有来技术 &#x1f525; 开源项目&#xff1a; youlai-mall &#x1f343; vue3-element-admin &#x1f343; youlai-boot &#x1f33a; 仓库主页&#xff1a; Gitee &#x1f4ab; Github &#x1f4ab; GitCode &#x1f496; 欢迎点赞…

Yapi详细安装过程(亲测可用)

1. 前置条件 1、Git 2、NodeJs&#xff08;7.6&#xff09; 3、Mongodb&#xff08;2.6&#xff09; 2. NodeJs的安装 1、获取资源 curl -sL https://rpm.nodesource.com/setup_8.x | bash - 2、安装NodeJS yum install -y nodejs 3、查看NodeJs和Npm node -v npm -v…

算法——分治

思想&#xff1a;分而治之&#xff0c;将大问题转化为若干个相同或相似的子问题。快排的题目常见的方法是利用三指针法将数组分三块搭配随机选择基准元素的思想 颜色分类&#xff08;分治_快排&#xff09; 颜色分类 题目解析 原地对它们进行排序&#xff0c;使得相同颜色的元…

Appium 图像识别技术 OpenCV

在我们做App自动化测试的时候&#xff0c;会发现很多场景下元素没有id、content-desc、text等等属性&#xff0c;并且有可能也会碰到由于开发采用的是自定义View&#xff0c;View中的元素也无法识别到&#xff0c;很多的自动化测试框架对此类场景束手无策。Appium在V1.9.0中有给…

Temu、Shein、OZON测评自养号,IP和指纹浏览器的优缺点分析

随着全球电子商务的飞速发展&#xff0c;跨境电商环境展现出巨大的潜力和机遇。然而&#xff0c;跨境卖家们也面临着更激烈的竞争、更严格的规定和更高的运营成本等挑战。为了在这个环境中脱颖而出&#xff0c;一些卖家尝试使用自动脚本程序进行浏览和下单。然而&#xff0c;这…

【LeetCode刷题-回溯】--216.组合总和III

216.组合总和III 方法&#xff1a;回溯 class Solution {public List<List<Integer>> combinationSum3(int k, int n) {List<List<Integer>> ans new ArrayList<>();Deque<Integer> path new ArrayDeque<>(); dfs(ans,path,n,k,1…

复杂背景下的低空无人机检测与跟踪算法

doi&#xff1a;10.11884/HPLPB202335.230026 大视场中的目标丢失后需要再次检测&#xff0c;但是大视场的检测比较耗时。但是根据实验发现丢失目标通常发生在无人机运动区域的320x320范围内&#xff0c;所以设计辅助网络&#xff0c;当目标丢失后&#xff0c;以320x320区域图像…

SI24R03国产自主可控RISC-V架构MCU低功耗2.4GHz收发芯片SoC

目录 RISC-V架构的优势SI24R03/04特性射频收发器模块特征MCU 模块特征 其他特征 RISC-V架构的优势 相对于目前主流的英特尔X86架构及ARM等架构来说&#xff0c;RISC-V架构具有指令精简、模块化、可扩展、开源、免费等优点。RISC-V的基础指令集只有40多条&#xff0c;加上其他基…

AI智剪:一键批量剪辑,高效助力创作无限可能

你是否曾经因为视频剪辑工作繁琐而感到烦恼&#xff1f;是否曾经因为视频剪辑效率低下而无法按时完成任务&#xff1f;如果你也有这样的困扰&#xff0c;那么AI智剪将为你提供解决方案。 第一步&#xff1a;首先进入媒体梦工厂主页面&#xff0c; 并在板块栏里选择“AI智剪”板…

脉冲群EFT整改措施和影响?|深圳比创达电子

一、什么是脉冲群EFT&#xff1f; 脉冲群EFT是一种电磁兼容性测试方法&#xff0c;用于评估电子设备在电力系统中的耐受能力。它模拟了由电网中的突然切换或开关操作引起的瞬态电磁干扰&#xff0c;并对设备的性能进行测试。 二、影响脉冲群EFT测试的因素 在进行脉冲群EFT测试…

模拟适配器设计方案:360-基于10G以太网的模拟适配器

基于10G以太网的模拟适配器 一、产品概述 基于10G以太网的模拟适配器是一款分布式高速数据采集系统&#xff0c;实现多路AD的数据采集&#xff0c;并通过10G以太网光纤远距离传输到存储计算服务器&#xff0c;计算控制指令能通过光纤返回给数据卡进行IO信号控制。产品基于…

如何在安装了巨魔2的iphone中运行Theos编译的本地化二进制工具:Bootstrap

如何在安装了巨魔2的iphone中运行Theos编译的本地化二进制工具:Bootstrap 一、首先从https://github.com/34306/iPA/releases/tag/bstr下载jb.zip、jb_with_jb_folder.zip、prefs_fix.ipa三个文件。 二、然后使用Filza文件管理器把jb.zip解压后复制到/var/containers/jb目录&…

【LangChain学习之旅】—(1) 何谓 LangChain

Reference&#xff1a;LangChain 实战课 【LangChain学习之旅】— 何谓 LangChain 如何理解 LangChainLangChain 中的具体组件LangChain调用ChatGPTLangChain代理功能 如何理解 LangChain 作为一种专为开发基于语言模型的应用而设计的框架&#xff0c;通过 LangChain&#xff…

【算法刷题】Day15

文章目录 1. 串联所有单词的子串题干&#xff1a;算法原理代码&#xff1a; 2. 最小覆盖子串题干&#xff1a;算法原理&#xff1a;1、暴力枚举 哈希表2、滑动窗口 哈希表 代码&#xff1a; 1. 串联所有单词的子串 原题链接 题干&#xff1a; 给定⼀个字符串 s 和⼀个字符串…