当前位置: 首页 > news >正文

使用 Three.js 后处理的粗略铅笔画效果

本文使用Three.js的后处理创建粗略的铅笔画效果。我们将完成创建自定义后处理渲染通道、在 WebGL中实现边缘检测、将法线缓冲区重新渲染到渲染目标以及使用生成和导入的纹理调整最终结果的步骤。翻译自Codrops,有改动。

Three.js 中的后处理

Three.js中的后处理是一种在绘制场景后将效果应用于渲染场景的方法。除了Three.js提供的所有开箱即用的后处理效果外,还可以通过创建自定义渲染通道来添加我们自己的滤镜。

自定义渲染过程本质上是一个函数,它接收场景图像并返回一个新图像,并应用所需的效果。我们可以将这些渲染通道想象成Photoshop中的图层效果————每个渲染通道都基于之前的效果输出应用新的滤镜。生成的图像是所有不同效果(滤镜)的组合。

在 Three.js 中启用后处理

要向我们的场景添加后处理效果,我们需要设置EffectComposer来进行场景渲染。这个EffectComposer将后处理效果按传递顺序叠加在一起。如果我们想让我们渲染的场景传递给下一个效果,我们需要先利用RenderPass创建一个后处理通道。

然后,在启动渲染循环的tick函数中,我们调用composer.render()来代替renderer.render(scene, camera)

const renderer = new THREE.WebGLRenderer()const composer = new EffectComposer(renderer)
const renderPass = new RenderPass(scene, camera)composer.addPass(renderPass)function tick() {requestAnimationFrame(tick)composer.render()
}tick()

有两种创建自定义后处理效果的方法:

1.创建自定义着色器并将其传递给ShaderPass实例,或者
2.通过扩展Pass类来创建自定义渲染通道。

因为我们希望我们的后处理效果获得比uniform和attribute更多的信息,所以我们将创建一个自定义渲染通道。

创建自定义渲染通道

一个自定义通道继承自Pass类,并具有三个方法:setSizerenderdispose,我们将主要关注render方法。

首先,我们扩展Pass类来创建自己的PencilLinesPass类,然后再实现我们自己的渲染逻辑。

import { Pass, FullScreenQuad } from 'three/examples/jsm/postprocessing/Pass'
import * as THREE from 'three'export class PencilLinesPass extends Pass {constructor() {super()}render(renderer: THREE.WebGLRenderer,: THREE.WebGLRenderTarget,readBuffer: THREE.WebGLRenderTarget) {if (this.renderToScreen) {renderer.setRenderTarget(null)} else {renderer.setRenderTarget(writeBuffer)if (this.clear) renderer.clear()}}
}

从上面代码中可以看出该render方法接受一个WebGLRenderer对象和两个WebGLRenderTarget对象(一个用于写入缓冲区,另一个用于读取缓冲区)。在Three.js中,渲染目标一般是我们可以渲染到场景的纹理,它们用于在通道之间发送数据。readBuffer从先前的渲染通道接收数据,在我们的例子中是默认的RenderPass;writeBuffer则是将数据发送到下一个渲染通道。

renderToScreen为true的时候,则意味着我们要将缓冲区发送到屏幕而不是渲染目标。渲染器的渲染目标设置为null的时候,默认就是为屏幕画布。

在这一点上,我们实际上并没有渲染任何东西,甚至没有通过readBuffer传入数据。为了渲染场景事物,我们需要创建一个FullscreenQuad和一个负责渲染的着色器材质,然后将着色器材质渲染到FullscreenQuad

为了测试一切设置是否正确,我们可以使用threejs内置的CopyShader来显示我们放入其中的任何图像。

import { Pass, FullScreenQuad } from 'three/examples/jsm/postprocessing/Pass'
import { CopyShader } from 'three/examples/jsm/shaders/CopyShader'
import * as THREE from 'three'export class PencilLinesPass extends Pass {fsQuad: FullScreenQuadmaterial: THREE.ShaderMaterialconstructor() {super()this.material = new THREE.ShaderMaterial(CopyShader)this.fsQuad = new FullScreenQuad(this.material)}dispose() {this.material.dispose()this.fsQuad.dispose()}render(renderer: THREE.WebGLRenderer,writeBuffer: THREE.WebGLRenderTarget,readBuffer: THREE.WebGLRenderTarget) {this.material.uniforms['tDiffuse'].value = readBuffer.textureif (this.renderToScreen) {renderer.setRenderTarget(null)this.fsQuad.render(renderer)} else {renderer.setRenderTarget(writeBuffer)if (this.clear) renderer.clear()this.fsQuad.render(renderer)}}
}

注意:我们将uniform变量tDiffuse传递给着色器材质。CopyShader已经内置了这个uniform,它代表要在屏幕上渲染显示的图像。如果你正在编写自己的ShaderPass,这个uniform将自动传递到你的着色器中。

剩下的就是通过将自定义渲染通道添加到EffectComposer来将自定义渲染通道连接到场景中,而且注意要在添加完RenderPass之后。

const renderPass = new RenderPass(scene, camera)
const pencilLinesPass = new PencilLinesPass()composer.addPass(renderPass)
composer.addPass(pencilLinesPass)

查看 Codesandbox 示例


具有自定义渲染通道和 CopyShader 的场景

用于创建轮廓的 Sobel 算子

我们需要能够告诉计算机根据我们的输入图像(即场景图像)检测边缘线条,我们将使用的这种边缘检测称为 Sobel 算子。

Sobel 算子通过查看图像一小部分的梯度来进行边缘检测————本质上是检查从一个值到另一个值的过渡有多尖锐。图像被分解成更小的“内核”,比如说是 3px x 3px 的正方形,其中中心像素是当前正在处理的像素。下图显示了它的样子:中心的红色方块代表当前正在评估的像素,其余方块是它的邻近像素。


3px x 3px 内核

然后通过获取像素值(亮度)并将其乘以基于其相对于被评估像素的位置的权重来计算每个邻近像素的加权值。这是通过权重在水平和垂直方向上偏置梯度来完成的。取两个值的平均值,如果它超过某个阈值,我们认为该像素表示边缘。


Sobel 算子的水平和垂直梯度

Three.js 已经为我们提供了SobelOperatorShader中的代码,我们可以将这段代码复制到我们的着色器材质中。

实现 Sobel 算子

我们现在需要添加我们自己的ShaderMaterial来代替CopyShader,以便我们可以控制顶点和片段着色器,以及发送给那些着色器的uniform。

// PencilLinesMaterial.ts
export class PencilLinesMaterial extends THREE.ShaderMaterial {constructor() {super({uniforms: {tDiffuse: { value: null },// 我们稍后会在这里传递画布大小uResolution: {value: new THREE.Vector2(1, 1)}},fragmentShader, vertexShader})}
}

然后我们需要在场景中使用我们的新着色器材质。

// PencilLinesPass.ts
export class PencilLinesPass extends Pass {fsQuad: FullScreenQuadmaterial: PencilLinesMaterialconstructor({ width, height }: { width: number; height: number }) {super()// 将材质更改为我们新的PencilLinesMaterialthis.material = new PencilLinesMaterial() this.fsQuad = new FullScreenQuad(this.material)// 将 uResolution 设置为当前画布的宽度和高度this.material.uniforms.uResolution.value = new THREE.Vector2(width, height)}
}

接下来,我们可以编写顶点和片段着色器。

除了设置gl_Position并将uv属性传递给片段着色器之外,顶点着色器并没有做其他事情。因为我们将图像渲染到FullscreenQuad,所以uv信息对应于任何给定片段在屏幕上的位置。

// vertex shader
varying vec2 vUv;void main() {vUv = uv;gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
}

片元着色器要复杂一些,所以我们逐行进行分解。首先,我们要使用Three.js已经提供的实现算法来实现Sobel算子。唯一的区别是我们想要控制我们如何计算每个像素的值,因为我们也将引入法线缓冲区的线检测。

float combinedSobelValue() {// 内核定义(在 glsl 中,矩阵按列优先顺序填充)const mat3 Gx = mat3(-1, -2, -1, 0, 0, 0, 1, 2, 1);// x方向内核const mat3 Gy = mat3(-1, 0, 1, -2, 0, 2, -1, 0, 1);// y方向内核// 获取片段的 3x3 邻域// 第一列float tx0y0 = getValue(-1, -1);float tx0y1 = getValue(-1, 0);float tx0y2 = getValue(-1, 1);// 第二列float tx1y0 = getValue(0, -1);float tx1y1 = getValue(0, 0);float tx1y2 = getValue(0, 1);// 第三列float tx2y0 = getValue(1, -1);float tx2y1 = getValue(1, 0);float tx2y2 = getValue(1, 1);// x方向的梯度值float valueGx = Gx[0][0] * tx0y0 + Gx[1][0] * tx1y0 + Gx[2][0] * tx2y0 +Gx[0][1] * tx0y1 + Gx[1][1] * tx1y1 + Gx[2][1] * tx2y1 +Gx[0][2] * tx0y2 + Gx[1][2] * tx1y2 + Gx[2][2] * tx2y2;// y方向的梯度值float valueGy = Gy[0][0] * tx0y0 + Gy[1][0] * tx1y0 + Gy[2][0] * tx2y0 +Gy[0][1] * tx0y1 + Gy[1][1] * tx1y1 + Gy[2][1] * tx2y1 +Gy[0][2] * tx0y2 + Gy[1][2] * tx1y2 + Gy[2][2] * tx2y2;// 总梯度的大小float G = (valueGx * valueGx) + (valueGy * valueGy);return clamp(G, 0.0, 1.0);
}

我们将当前像素的偏移量传递给getValue函数,在获取邻域像素的值。目前,我们仅需要评估漫反射缓冲区的值,我们将在下一步中添加法线缓冲区。

float valueAtPoint(sampler2D image, vec2 coord, vec2 texel, vec2 point) {vec3 luma = vec3(0.299, 0.587, 0.114);return dot(texture2D(image, coord + texel * point).xyz, luma);
}float diffuseValue(int x, int y) {return valueAtPoint(tDiffuse, vUv, vec2(1.0 / uResolution.x, 1.0 / uResolution.y), vec2(x, y)) * 0.6;
}float getValue(int x, int y) {return diffuseValue(x, y);
}

valueAtPoint函数可以输入任何纹理(漫反射或法线)并返回指定点的灰度值。luma向量用于计算颜色的亮度,从而将rgb颜色转换为灰度值。这个实现来自glsl-luma。

因为getValue函数只考虑漫反射缓冲区,这意味着场景中的任何边缘都将被检测到,包括由投射的阴影创建的边缘。这也意味着例如物体的轮廓,如果它们与周围环境(投射的阴影)融合得太好,可能会被忽略。为了捕获那些缺失的边缘,我们接下来将从法线缓冲区添加边缘检测。

最后,我们在主函数中调用 Sobel 算子,如下所示:

void main() {float sobelValue = combinedSobelValue();sobelValue = smoothstep(0.01, 0.03, sobelValue);vec4 lineColor = vec4(0.32, 0.12, 0.2, 1.0);if (sobelValue > 0.1) {gl_FragColor = lineColor;} else {gl_FragColor = vec4(1.0);}
}

查看 Codesandbox 示例

创建一个法线缓冲区渲染

为了获得合适的轮廓,Sobel算子通常应用于场景的法线和深度缓冲区,因此会捕获对象的轮廓,但不会捕获对象内的线条。Omar Shehata 在他的How to render outlines in WebGL教程中描述了这种方法。出于只是实现粗略铅笔效果的目的,我们不需要完整的边缘检测,但我们确实希望使用法线来获得更完整的边缘。

由于法线是表示对象表面每个点方向的向量,因此通常用颜色表示以获取包含场景中所有法线数据的图像。这张图被称为“法线缓冲区”。

为了创建一个法线缓冲区,首先我们需要在PencilLinesPass构造函数中创建一个新的渲染目标。我们还需要在类上创建一个MeshNormalMaterial,因为我们将在渲染法线缓冲区时使用它来覆盖场景的默认材质。

const normalBuffer = new THREE.WebGLRenderTarget(width, height)normalBuffer.texture.format = THREE.RGBAFormat
normalBuffer.texture.type = THREE.HalfFloatType
normalBuffer.texture.minFilter = THREE.NearestFilter
normalBuffer.texture.magFilter = THREE.NearestFilter
normalBuffer.texture.generateMipmaps = false
normalBuffer.stencilBuffer = false
this.normalBuffer = normalBufferthis.normalMaterial = new THREE.MeshNormalMaterial()

为了渲染通道内的场景,我们还需要通过渲染通道的构造函数来传入scene和camera。

// PencilLinesPass.ts 构造函数
constructor({ ..., scene, camera}: { ...; scene: THREE.Scene; camera: THREE.Camera }) {super()this.scene = scenethis.camera = camera...
}

在渲染通道的render方法中,我们想要使用覆盖默认材质的法线材质重新渲染场景。我们将renderTarget设置为normalBuffer,并像往常一样使用WebGLRenderer渲染场景。唯一的区别是,渲染器不是使用场景的默认材质渲染到屏幕,而是使用法线材质渲染到我们的渲染目标(此处即为我们的normalBuffer)。然后我们将normalBuffer.texture传递给着色器材质。overrideMaterial参数表示强制使用定义的材质渲染场景中的所有内容。

renderer.setRenderTarget(this.normalBuffer)
const overrideMaterialValue = this.scene.overrideMaterialthis.scene.overrideMaterial = this.normalMaterial
renderer.render(this.scene, this.camera)
this.scene.overrideMaterial = overrideMaterialValuethis.material.uniforms.uNormals.value = this.normalBuffer.texture
this.material.uniforms.tDiffuse.value = readBuffer.texture

如果此时我们利用texture2D(uNormals,vUv);将法线缓冲区的值赋给gl_FragColor,渲染结果将是下图所示:

当前场景的法线缓冲区

在自定义材质的片段着色器中,我们修改getValue函数,让它包含漫反射缓冲区和法线缓冲区的 Sobel 算子。如果我们在这里只计算法线缓冲区,会发现平面阴影的边缘就没有了,因为平面法线是没有过渡的。

float normalValue(int x, int y) {return valueAtPoint(uNormals, vUv, vec2(1.0 / uResolution.x, 1.0 / uResolution.y), vec2(x, y)) * 0.3;
}float getValue(int x, int y) {return diffuseValue(x, y) + normalValue(x, y);
}

查看 Codesandbox 示例

为着色和波浪线添加生成的纹理噪声

有两种方法可以将噪声带入后处理效果:

  1. 通过在着色器中由程序生成噪声,或者
  2. 通过使用带有噪声的图像并将其应用为纹理。

两者都提供了不同级别的灵活性和控制。对于噪声函数,我们使用Inigo Quilez的梯度噪声实现算法,因为它在应用于“着色”效果时提供了很好的噪声均匀性。

这个噪声函数是在获取Sobel算子的值时调用的,并专门作用于法线值,所以片段着色器中getValue的函数变化如下:

float getValue(int x, int y) {float noiseValue = noise(gl_FragCoord.xy);noiseValue = noiseValue * 2.0 - 1.0;noiseValue *= 10.0;return diffuseValue(x, y) + normalValue(x, y) * noiseValue;
}

这样得出来的结果是在法向量值发生变化时,对象曲线上形成带纹理的铅笔线和点画效果。请注意,平面对象(如Plane)不会产生这些效果,因为它们的法线值没有任何变化。

此效果的下一步也是最后一步是为线条添加扭曲。为此,我们使用了在Photoshop中使用渲染云效果创建的纹理文件。


在 Photoshop 中创建的生成的云纹理

云纹理通过一个uniform变量传递给着色器,与漫反射和法线缓冲区的方式相同。一旦着色器可以访问纹理,我们就可以对每个片段的纹理进行采样,并使用它来偏移我们在缓冲区中读取的位置。本质上,我们通过扭曲我们正在读取的图像来获得波浪线效果。因为纹理的噪点是平滑的,线条不会出现锯齿状和不规则的情况。

float normalValue(int x, int y) {float cutoff = 50.0;float offset = 0.5 / cutoff;float noiseValue = clamp(texture(uTexture, vUv).r, 0.0, cutoff) / cutoff - offset;return valueAtPoint(uNormals, vUv + noiseValue, vec2(1.0 / uResolution.x, 1.0 / uResolution.y), vec2(x, y)) * 0.3;
}

查看 Codesandbox 示例

结论

有许多技术可以在3D中创建手绘或素描效果。我们可以通过基于噪声纹理调制被认为是边缘的阈值来调整线条粗细。我们还可以将Sobel算子应用于深度缓冲区,完全忽略漫反射缓冲区,以获得没有轮廓阴影的轮廓对象。我们可以根据场景中的照明信息而不是基于对象的法线来添加生成的噪声。接下来我会将这种效果应用到cesium和mapbox上。

相关文章:

使用 Three.js 后处理的粗略铅笔画效果

本文使用Three.js的后处理创建粗略的铅笔画效果。我们将完成创建自定义后处理渲染通道、在 WebGL中实现边缘检测、将法线缓冲区重新渲染到渲染目标以及使用生成和导入的纹理调整最终结果的步骤。翻译自Codrops,有改动。 Three.js 中的后处理 Three.js中的后处理是一…...

推荐一些不常见的搜索引擎

5.雅虎网来自 Yahoo.com 的屏幕截图,2023 年 2 月截至 2022 年 1 月,Yahoo.com(Verizon Media)的搜索市场份额为 11.2%。雅虎的优势在于多元化,除搜索外还提供电子邮件、新闻、金融等服务。二十多年来,雅虎…...

RabbitMQ工作模式

目录1.Work queues工作队列模式1.1 模式说明1.2 代码1.3 测试1.4 小结2.订阅模式类型3.Publish/Subscribe发布与订阅模式3.1 模式说明3.2 代码3.3 测试3.4 小结4.Routing路由模式4.1 模式说明4.2 代码4.3 测试4.4 小结5.Topics通配符模式5.1 模式说明5.2 代码5.3 测试5.4 小结6…...

机器学习在预测脊髓型颈椎病中的应用:一项28名参与者的事后初步研究

机器学习在预测脊髓型颈椎病中的应用:一项28名参与者的事后初步研究 Machine Learning for the Prediction of Cervical Spondylotic Myelopathy: A Post Hoc Pilot Study of 28 Participants 简单说:训练了两个模型:1)预测脊髓型颈椎病诊断&#xff0…...

【智能计算数学】微积分

高数问题解决流程引例:回归回归引例:分类分类线性可分FLD线性不可分智能计算讨论范围下降法为什么要用下降法?- 解析解很难写出公式或很复杂难计算有哪些常用的下降法?- 梯度下降&高斯-牛顿法梯度下降(Gradient De…...

win10+RTX4070ti+libtorch部署

环境cuda 11.7、cudnn8.6.0、libtorch1.13.1cu117 注意: 1)libtorch官网进不去的可直接下载 Release version https://download.pytorch.org/libtorch/cu117/libtorch-win-shared-with-deps-1.13.1%2Bcu117.zip Debug version https://download.pytorch.…...

【Python百日进阶-Web开发-Vue3】Day518 - Vue+ts后台项目5:用户列表

文章目录 一、获取用户列表的数据1.1 定义用户列表和角色列表的接口src/request/api.ts1.2 获取用户列表数据src/views/UserView.vue二、定义用户列表数据类型2.1 src/type/user.ts三、展示用户列表内容3.1 element-plus中的Select 选择器3.2 element-plus中的表格插槽3.3 展示…...

Linux内核转储---kdump原理梳理

文章目录Kexec和Kdump设计的区别kexeckdumpKdump的执行流程kexec的实现用户空间kexec内核空间vmcoreKdump的实现可以分为两部分:内核和用户工具。内核提供机制,用户工具在这些机制上实现各种转储策略,内核机制对用户工具的接口是一个系统调用…...

【C++】从0到1入门C++编程学习笔记 - 实战篇:演讲比赛流程管理系统

文章目录一、演讲比赛程序需求1.1 比赛规则1.2 程序功能1.3 程序效果图:二、项目创建2.1 创建项目2.2 添加文件三、创建管理类3.1创建文件3.2 头文件实现3.3 源文件实现四、菜单功能4.1 添加成员函数4.2 菜单功能实现4.3 测试菜单功能五、退出功能5.1 提供功能接口5…...

04 OpenCV位平面分解

1 基本概念 位平面分解的核心思想是将图像的每一个像素分解为多个二进制位,分别存储在不同的位平面上。例如,如果一个图像是8位深度的,则可以分解为8个位平面,每个位平面上存储一个二进制位。 位平面分解在图像压缩中有着重要的…...

Onvif协议如何判断摄像机支持 —— 筑梦之路

有人就问什么是Onvif协议呢? 全称为:Open Network Video Interface Forum.缩写成Onvif。 翻译过来是:开放型网络视频接口论坛,目的是确保不同安防厂商的视频产品能够具有互通性,这样对整体安防行业才是良性发展。 现…...

情人节new一个对象给你

今天情人节,有没对象的吗?假设你不知道new怎么用,每个人都有两种身份,一种没对象的人,这个时候new一个对象给你,一种是有对象的人,这个delete对象。等你学完这个new和delete知识点,无…...

linux篇【15】:应用层-网络https协议

目录 一.HTTPS介绍 1.HTTPS 定义 2.HTTP与HTTPS (1)端口不同,是两套服务 (2)HTTP效率更高,HTTPS更安全 3.加密,解密,密钥 概念 4.为什么要加密? 5.常见的加密方式…...

索引-性能分析-explain

explain 执行计划 explain 执行计划各字段含义 1)id 就是代表 sql 的执行顺序或者表的执行顺序;id相同从上往下执行,id不同,id值越大越先执行;(注:有子查询时就会出现sql执行顺序)…...

mbedtls加密组件使用示例

1 mbedtls aes组件的使用 1.1 AES ECB加解密接口使用 int main(int argc, char *argv[]) {char key[256];char *inbuf calloc(1, 257);char *outbuf calloc(1, 257);char *buf calloc(1,257);char *tmp_outbuf outbuf;char *tmp_buf buf;mbedtls_aes_context aes_ctx;mb…...

如何量测太阳光模拟器的光谱致合度?

太阳模拟器是根据国际法规JIS、IEC60904、美国材料试验协会开发设计的AAA级太阳模拟器。对于100毫米100毫米和200毫米200毫米的光斑尺寸,光斑强度的输出功率范围可以从0.1到1太阳光强度。此外,还提供了灵活的出光方向,以满足用户的研究需求&a…...

网络安全领域中CISP证书八大类都有什么

CISP​注册信息安全专业人员 注册信息安全专业人员(Certified Information Security Professional),是经中国信息安全产品测评认证中心实施的国家认证,对信息安全人员执业资质的认可。该证书是面向信息安全企业、信息安全咨询服务…...

17- 梯度提升回归树GBRT (集成算法) (算法)

梯度提升回归树: 梯度提升回归树是区别于随机森林的另一种集成方法,它的特点在于纠正与加强,通过合并多个决策树来构建一个更为强大的模型。该模型即可以用于分类问题,也可以用于回归问题中。在该模型中,有三个重要参数分别为 n_…...

05 OpenCV色彩空间处理

色彩空间(Color Space)是一种用于描述颜色的数学模型,它将颜色表示为多维向量或坐标,通常由三个或四个独立的分量来表示。不同的色彩空间在颜色的表示方式、可表达颜色的范围、计算速度和应用场景等方面存在差异,不同的…...

【CS224图机器学习】task1 图机器学习导论

前言:本期学习是由datawhale(公众号)组织,由子豪兄讲解的202302期CS224图机器学习的学习笔记。本次学习主要针对图机器学习导论做学习总结。1.什么是图机器学习?通过图这种数据结构,对跨模态数据进行整理。…...

Powershell Install SQL Server 2022

前言 SQL Server 2022 (16.x) 在早期版本的基础上构建,旨在将 SQL Server 发展成一个平台,以提供开发语言、数据类型、本地或云环境以及操作系统选项。 SQL Server Management Studio (SSMS) 是一种集成环境,用于管理从 SQL Server 到 Azure SQL 数据库的任何 SQL 基础结构…...

Jetson NX2 装机过程

1.固态硬盘安装完成后,系统配置 df -h 查看硬盘使用情况 2.查看Jetson NX的IP地址,以下两个都行 ifconfig ip address show 3.Jetson NX2安装arm64的annaconda3,安装有问题报错illegal instruction,未解决。 4.VNC远程登录 …...

初始C++(四):内联函数

文章目录一.内联函数概念二.内联函数用法三.内联函数的特性四.内联函数和宏一.内联函数概念 以inline修饰的函数叫做内联函数,编译时C编译器会在调用内联函数的地方展开,没有函数调用建立栈帧的开销,内联函数提升程序运行的效率。 二.内联函…...

九、初识卷积

文章目录1、通过边缘检测认识卷积2、Padding3、Strid Convelution4、RGB图像的卷积THE END1、通过边缘检测认识卷积 \qquad在使用神经网络进行图像识别时,神经网络的前几层需要完成对图像的边缘检测任务,所谓的边缘检测就是让计算机识别出一张图片的垂直…...

【Linux】【编译】编译调试过程中如何打印出实际的编译命令

🐚作者简介:花神庙码农(专注于Linux、WLAN、TCP/IP、Python等技术方向)🐳博客主页:花神庙码农 ,地址:https://blog.csdn.net/qxhgd🌐系列专栏:Linux技术&…...

linux安装jdk

step1 下载jdk 到下面的网站下载需要的jdk安装包版本。 Java Downloads | Oracle step2 复制到opt目录 其中user_name对应自己的home目录的用户文件夹 sudo cp /home/user_name//home/czh/Downloads/jdk-17_linux-x64_bin.tar.gz /opt/ step3 到opt目录解压安装包&#xf…...

迅为iTOP-3A5000龙芯开发板安装UOS操作系统

3A5000板卡采用全国产龙芯3A5000处理器,基于龙芯自主指令系统(LoongArch),市面上龙芯3A5000主板价格都在上万元,可以说是非常贵了, 迅为全新推出了款千元内的iTOP-3A5000开发板,这款板卡各方面的配置也是第…...

Firefox 110, Chrome 110, Chromium 110 官网离线下载 (macOS, Linux, Windows)

Mozilla Firefox, Google Chrome, Chromium, Apple Safari 请访问原文链接:https://sysin.org/blog/chrome-firefox-download/,查看最新版。原创作品,转载请保留出处。 作者主页:www.sysin.org 天下只剩三种(主流&am…...

如何使用ArcGIS转换坐标

1.概述大家都知道ArcGIS提供了坐标转换功能,在我们手里的数据坐标系千差万别,经常会遇到转换坐标的时候,那么是否可以用ArcGIS进行转换?答案是肯定的,但是转换的过程比较复杂,这里为大家介绍一下转换的方法…...

链表基本原理

链表基本原理1.链表1.1 基本原理1.2 链表大O记法表示2. 链表操作2.1 读取2.2 查找2.3 插入2.4 删除3.链表代码实现1.链表 1.1 基本原理 节点 组成链表的数据格子不是连续的。可以分布在内存的各个位置。这种不相邻的格子就叫结点。每个结点保存数据还保存着链表里的下一结点的…...

2323wan网页游戏/河北seo人员

HighDPI是windows7提出的一种新特性,使应用程序更加容易地为视觉障碍者服务,使程序随着窗口一样自动缩放, 展示完美的效果,下面我们来实践一下,如何开发基于HIGHDPI的应用程序 首先体验下,在英文windows7…...

域名服务器ip查询网站/谷歌网站推广优化

http://blog.csdn.net/xingxing_yan/article/details/54730068 转载 http://www.cnblogs.com/jiayongji/p/5560806.html 一. 概述 用过华为手机的人应该知道华为手机系统应用中的加载动画是一个小球绕着圆圈旋转,之前有一个项目用过类似的功能,所以写了一…...

内网怎么做网站服务器/论坛seo教程

1、HTTP标头值 Content-type application/x-www-form-urlencoded ,post参数值需要URL编码 2、测试接口签约短信验证码为固定值:111111 3、参数不能有空值 4、测试支付接口规则:金额为奇数交易成功,偶数时会交易失败。 &#xff0…...

聊城高新区建设局网站/百度官网进入

https://mp.weixin.qq.com/s/OwWUDxHY4Th6decmJeMTgA、 双亲委派参考...

百度网站排名怎么做/seo是什么意思新手怎么做seo

使用公式n&#xff01;/ r&#xff01;*(nr)&#xff01;计算二项式系数(c(n,r)或nCr)。以下是Java程序&#xff0c;找出给定整数的二项式系数。程序import java.util.Scanner;public class BinomialCoefficient {public static long fact(int i) {if(i < 1) {return 1;}ret…...

科技企业网站/搜索引擎营销包括

1、__ new__, __ init__, __ call__ __ new__(cls, *args, **kwargs) 创建对象时调用&#xff0c;返回当前对象的一个实例;注意&#xff1a;这里的第一个参数是cls即class本身 __ init__(self, *args, **kwargs) 创建完对象后调用&#xff0c;对当前对象的实例的一些初始化&…...