论文阅读:Real-time Controllable Denoising for Image and Video
这篇文章是 CVPR 2023 的一篇文章,探讨了在图像与视频降噪中,如何实时控制降噪强度的问题。
Abstract
图像或者视频降噪,是在细节与平滑度之间的一个微妙的平衡,因为噪声与细节都属于高频信息,降噪在去除噪声的同时,也会对纹理细节造成一定的损害,而且最终的图像效果与人的主观感受有关,所以降噪强度也是一个众口难调的问题。所以文章的主旨非常明确,就是要做可控的降噪,而且是实时可控。这个在传统的降噪方法中,可以通过调整算法中的某些超参进行控制。不过对于目前主流的神经网络一类的方法来说,调整降噪强度,需要每次重新跑一遍推理,这个对于实时性要求很高的场景来说,这种耗时是很难接受的。所以这篇文章提出了一种可以实时控制降噪程度的方法,方法的名字也很直白,Real-time Controllable Denoising (RCD),这个方法可以只用一次推理,实现不同程度的降噪水平。RCD 主要是把降噪网络的最后一层的输出,通常是一个单一的 noise map,替换成了一个轻量级的模型,该模型可以输出多个 noise maps。而且文章作者设计了一种新的噪声去相关的处理方式,以保证输出的多个 noise map 是正交的,类似一组正交基,然后任意的降噪强度,可以由这组正交集插值表示。这个过程不依赖网络,也不需要网络的推理。这个类似一个 plug-and-play 的模块,可以接在不同的降噪模型上面使用,并取得很好的降噪效果。
Methods
Conventional Deep Denoising
文章先大概介绍了一下之前基于深度学习的降噪方法,主要是基于学习的方法,利用神经网络强大的特征学习能力,去实现传统方法中的滤波方法。绝大部分降噪方法通过回归预测一个噪声图来构建清晰图与噪声图之间的关系。特别的,给定一张输入的噪声图 I n \mathbf{I}_n In 以及一个模型, M : R H × W × C → R H × W × C \mathcal{M}: \mathbb{R}^{H \times W \times C} \rightarrow \mathbb{R}^{H \times W \times C} M:RH×W×C→RH×W×C,我们可以预测清晰图与噪声图之间满足如下关系: I c = I n + M ( I n ) \mathbf{I}_c = \mathbf{I}_n + \mathcal{M}(\mathbf{I}_n) Ic=In+M(In), M \mathcal{M} M 表示神经网络模型,通过学习优化的方法更新模型的参数。这种方法我们可以看到,最终输出的是单张清晰图像,无法显式地进行降噪的调整。
- 图2
图 2 展示了文章的 RCD 方法与传统的可控降噪方法之间的根本差异。与依赖控制网络的传统方法相比,RCD 流程生成了强度/级别不同的可编辑噪声,通过外部参数提供显性的控制,并实现了无网络的实时降噪编辑。RCD 提供的实时编辑功能为许多以前使用传统技术无法实现的应用创造了新的机会,例如在线视频降噪编辑,甚至在播放过程中(例如,为 ISP 调优工程师进行手机摄像头视频质量调优),以及在端侧设备和嵌入式系统上部署可控降噪。由于 RCD 的编辑阶段仅涉及图像插值,用户可以在性能较低的设备上编辑他们想要的结果,而无需使用 GPU/DSP。
Pipeline Overview
接下来作者介绍文章的方法,Real-time Controllable Denoising (RCD),整体的算法框架如图 3 所示,
- 图 3
RCD 包括三部分:
- 第一部分是一个 backbone 网络, M b : R H × W × C → R H × W × L C \mathcal{M}_b: \mathbb{R}^{H \times W \times C} \rightarrow \mathbb{R}^{H \times W \times LC} Mb:RH×W×C→RH×W×LC,这个网络会生成多张不同噪声水平的 noise maps,其中 L 表示定义好的噪声水平数量
- 第二部分是一个噪声解耦模块,将 backbone 网络输出的各个 noise maps 进行正交化,这样可以方便后面的调整
- 第三部分是一个 AutoTune 模块,给定一组控制参数,生成最好的降噪效果
假设 backbone 网络输出一组噪声图 noise maps, { N i } i = 1 L \{\mathcal{N}_i\}_{i=1}^{L} {Ni}i=1L,这组噪声图会经过后面的 Noise Decorrelation (ND) 模块,将噪声图正交化,类似生成一组基, { N ~ i } i = 1 L \{\tilde{\mathcal{N}}_i\}_{i=1}^{L} {N~i}i=1L,然后对 noise map 的这组基进行线性叠加,可以得到不同程度的降噪结果
I c = I n + ∑ i = 1 L c ˉ i N ~ i (1) \mathbf{I}_c = \mathbf{I}_n + \sum_{i=1}^{L} \bar{c}_i \tilde{\mathcal{N}}_i \tag{1} Ic=In+i=1∑LcˉiN~i(1)
其中, ∑ i = 1 L c ˉ i = 1 \sum_{i=1}^{L} \bar{c}_i = 1 ∑i=1Lcˉi=1
Multi-level Noise Generation
给定一张输入的噪声图像 I n \mathbf{I}_n In,backbone 网络的目标是输出一组 noise maps, { N i } i = 1 L \{\mathcal{N}_i\}_{i=1}^{L} {Ni}i=1L,这组噪声图对应事先定义好的噪声水平,比如噪声水平为 { 5 , 10 , 15 , . . . , 60 } \{5, 10, 15, ..., 60\} {5,10,15,...,60},因此,可以定义如下:
σ ( N i ) = l i , ∀ i ∈ 1 , 2 , . . . , L (2) \sigma(\mathcal{N}_i) = l_i, \forall i \in 1, 2, ..., L \tag{2} σ(Ni)=li,∀i∈1,2,...,L(2)
其中, σ \sigma σ 表示噪声水平的估计,计算每张 noise map 的标准差,为了得到多张 noise maps,文章在设计 backbone 网络的时候,把最后一层的卷积层做了替换,每个噪声水平的 noise map 通过如下的归一化形式得到:
N i = l i M b ( I n ) i σ ( M b ( I n ) i ) , ∀ i ∈ 1 , 2 , . . . , L (3) \mathcal{N}_i = l_i \frac{\mathcal{M_b}(\mathbf{I}_n)^{i}}{\sigma(\mathcal{M_b}(\mathbf{I}_n)^{i})}, \forall i \in 1, 2, ..., L \tag{3} Ni=liσ(Mb(In)i)Mb(In)i,∀i∈1,2,...,L(3)
其中, M b ( I n ) ∈ R H × W × L C \mathcal{M_b}(\mathbf{I}_n) \in \mathbb{R}^{H \times W \times LC} Mb(In)∈RH×W×LC 是网络的输出, M b ( I n ) i ∈ R H × W × C \mathcal{M_b}(\mathbf{I}_n)^{i} \in \mathbb{R}^{H \times W \times C} Mb(In)i∈RH×W×C 表示某个噪声水平下的在通道维度的分量,那么式 3 得到的 N i \mathcal{N}_i Ni 可以看成是某个噪声水平下的 noise map。
文章也提到说,不同于之前的一些控制降噪程度的方法隐式地在网络中进行插值,文章提出的方法,通过求出不同噪声水平的 noise maps,然后可以显示地线性插值得到不同程度的降噪,通过这种方法,可以通过改变加权系数 c c c 从而实现快速实时的交互式可控降噪。
不过,因为网络直接输出的noise maps N i \mathcal{N}_i Ni 一般来说是高度相关的,这对于 noise map 的线性加权带来很多问题,为了让每个 noise map 之间的相关性尽量减少,文章提出了 Noise Decorrelation (ND) 模块。
Noise Decorrelation
Noise Decorrelation 模块是用来对 backbone 网络进行正则,以使得网络可以生成不同噪声水平的 noise maps。这个模块本身没有额外的参数,主要是通过统计计算,以让 N i \mathcal{N}_i Ni 之间尽量不相关,即, c o v ( N i , N j ) ≈ 0 , ∀ i , j ∈ { 1 , 2 , . . . , L } \mathbf{cov}(\mathcal{N}_i, \mathcal{N}_j) \approx 0, \forall i, j \in \{1, 2,..., L \} cov(Ni,Nj)≈0,∀i,j∈{1,2,...,L},其中 c o v \mathbf{cov} cov 表示求两个向量的协方差系数。
对于每个 noise map N i \mathcal{N}_i Ni,先进行维度变换, N i ∈ R 1 × M \mathcal{N}_i \in \mathbb{R}^{1 \times M} Ni∈R1×M,其中, M = H W C M=HWC M=HWC,相当于将之前的一个张量重新变成一个一维向量,然后将 L L L 张 noise map 叠在一起,得到 N ∈ R L × M \mathbf{N} \in \mathbb{R}^{L \times M} N∈RL×M,然后计算协方差矩阵, Σ = 1 M − 1 ( N − N ˉ ) ( N − N ˉ ) T {\Sigma} = \frac{1}{M-1}(\mathbf{N} - \bar{\mathbf{N}})(\mathbf{N} - \bar{\mathbf{N}})^{T} Σ=M−11(N−Nˉ)(N−Nˉ)T,其中, N ˉ \bar{\mathbf{N}} Nˉ 表示均值向量。
为了实现 Noise Decorrelation,文章求解了协方差矩阵的逆开根号矩阵 Σ − 1 / 2 {\Sigma}^{-1/2} Σ−1/2,这个求解为了提升效率,文章使用了牛顿迭代法:
Σ 0 = I Σ k = 1 2 ( 3 Σ k − 1 − ( Σ k − 1 ) 3 Σ ) , k = 1 , 2 , . . . T (4) \Sigma_0 = \mathbf{I} \\ \Sigma_k = \frac{1}{2}(3\Sigma_{k-1} - (\Sigma_{k-1})^3\Sigma), k=1,2,...T \tag{4} Σ0=IΣk=21(3Σk−1−(Σk−1)3Σ),k=1,2,...T(4)
其中, T T T 表示总的迭代次数,文章中提到 T 一般取 3 或者 4 基本可以收敛到合理范围。求得 Σ − 1 / 2 {\Sigma}^{-1/2} Σ−1/2 的近似值之后,可以得到解耦后的 noise map, N ~ = N Σ − 1 / 2 \tilde{\mathbf{N}} = \mathbf{N} \Sigma^{-1/2} N~=NΣ−1/2,然后将 N ~ \tilde{\mathbf{N}} N~ 进一步做变换,得到 L L L 张可编辑的 noise map, N ~ i \tilde{\mathcal{N}}_i N~i, 解耦后的 nosie map 有非常好的线性性质,可以满足如下的式子:
V a r ( ∑ i = 1 L c i N ~ i ) = ∑ i = 1 L c i 2 V a r ( N ~ i ) (5) \mathbf{Var}(\sum_{i=1}^{L} c_i \tilde{\mathcal{N}}_i) = \sum_{i=1}^{L} c_i^2 \mathbf{Var}(\tilde{\mathcal{N}}_i) \tag{5} Var(i=1∑LciN~i)=i=1∑Lci2Var(N~i)(5)
公式 5 展示了最终的噪声水平与控制参数 c i c_i ci 之间的关系,除此之外,Noise Decorrelation 模块可以促使模型取学习不同水平下的噪声形式,以增强降噪模型的表达能力。图 4 展示了 ND 模块如何发挥作用。有了 ND 模块作为正则, ∣ Σ ∣ F |\Sigma|_F ∣Σ∣F 可以趋近于 0,从而可以让模型通过线性加权得到想要的噪声强度,如果没有 ND 模块,噪声水平难以保证与想要的设定值一致。
- 图 4
AutoTune Module
有了上面介绍的 Noise Decorrelation 模块输出的 noise maps,接下来 AutoTune 模块将预测一组模型建议的控制参数 { c i } i = 1 L \{c_i\}_{i=1}^{L} {ci}i=1L 进而生成最终的降噪效果。用户可以在这组控制参数的基础上,进行调整,从而得到不同强度的降噪结果。AutoTune 模块也是一个非常轻量化的模块,直接用一个单层的模型,利用 t-softmax 激活函数进行计算:
c i = e A ( f ) i τ ∑ j = 1 n A ( f ) j τ c_i = \frac{e^{ \frac{\mathcal{A(f)_i}}{\tau}} }{\sum_{j=1}^{n} \frac{\mathcal{A(f)_j}}{\tau}} ci=∑j=1nτA(f)jeτA(f)i
其中 A \mathcal{A} A 表示一个 NN 网络层, f f f 表示输入的特征图, τ = 0.05 \tau = 0.05 τ=0.05 表示温度系数,为了让 backbone 模型尽量高效,文章直接用未曾归一的模型输出作为特征图,如图 3 中的模块 C 所示。
New Cardinality for Denoising Control
与之前仅仅调节噪声强度的方法不同,文章提出的 RCD 方案可以让用户在给定噪声强度的情况下,通过调节 { c i } \{c_i\} {ci} 进一步优化降噪结果,只要关于噪声水平 l i l_i li 关于 c i c_i ci 的加权平均和是固定的,公式 5 已经证明,当 ∑ i = 1 L c i 2 V a r ( N ~ i ) = ∑ i = 1 L c i 2 l i 2 \sum_{i=1}^{L} c_i^2 \mathbf{Var}(\tilde{\mathcal{N}}_i) = \sum_{i=1}^{L} c_{i}^{2}l_{i}^{2} ∑i=1Lci2Var(N~i)=∑i=1Lci2li2 不变的时候,那么最终输出结果的方差 V a r ( ∑ i = 1 L c i N ~ i ) \mathbf{Var}(\sum_{i=1}^{L} c_i \tilde{\mathcal{N}}_i) Var(∑i=1LciN~i) 也是固定的,在保持 ∑ i = 1 L c i 2 l i 2 \sum_{i=1}^{L} c_{i}^{2}l_{i}^{2} ∑i=1Lci2li2 不变的情况下,通过改变 l i l_i li,即引入不同噪声水平的 noise map N i \mathcal{N}_i Ni,可以优化得到不同的降噪结果。
Optimization Targets
为了让模型对不同的噪声水平的组合 ∑ i = 1 L c i N ~ i \sum_{i=1}^{L} c_i \tilde{\mathcal{N}}_i ∑i=1LciN~i 都有一个好的降噪效果,我们采用了一种多级并行训练策略,通过最小化每个级别噪声输出与真实噪声之间的差异来实现,即:
L l e v e l = 1 L ∑ i = 1 L L ( I g t , I n + N ~ i ) (6) \mathcal{L}_{level} = \frac{1}{L} \sum_{i=1}^{L} \mathcal{L}(\mathbf{I}_{gt}, \mathbf{I}_n + \tilde{\mathcal{N}}_i) \tag{6} Llevel=L1i=1∑LL(Igt,In+N~i)(6)
结合 AutoTune 模块的输出,最终总的 loss 函数为:
L t o t a l = λ L l e v e l + L ( I g t , I n + ∑ i = 1 L c ˉ i N ~ i ) (7) \mathcal{L}_{total} = \lambda \mathcal{L}_{level} + \mathcal{L}(\mathbf{I}_{gt}, \mathbf{I}_n + \sum_{i=1}^{L} \bar{c}_i \tilde{\mathcal{N}}_i) \tag{7} Ltotal=λLlevel+L(Igt,In+i=1∑LcˉiN~i)(7)
其中, λ = 0.1 \lambda = 0.1 λ=0.1 表示两种 loss 的权重分配。
文章在仿真的高斯分布噪声以及真实噪声分布的数据集上都进行了实验。
相关文章:

论文阅读:Real-time Controllable Denoising for Image and Video
这篇文章是 CVPR 2023 的一篇文章,探讨了在图像与视频降噪中,如何实时控制降噪强度的问题。 Abstract 图像或者视频降噪,是在细节与平滑度之间的一个微妙的平衡,因为噪声与细节都属于高频信息,降噪在去除噪声的同时&…...

【Kubernetes】虚拟 IP 与 Service 的代理模式
虚拟 IP 与 Service 的代理模式 1.userspace 代理模式2.iptables 代理模式3.IPVS 代理模式 由于 Service 的默认发布类型是 ClusterlP,因此也可以把 ClusterIP 地址叫作 虚拟 IP 地址。在 Kubernetes 创建 Service 时,每个节点上运行的 kube-proxy 会自动…...
深度学习·Pytorch
以下代码源自李沐 自定义模块类 继承module类 继承nn.Module重写构造函数前向传播 class MLP(nn.Module):# 用模型参数声明层。这里,我们声明两个全连接的层def __init__(self):# 调用MLP的父类Module的构造函数来执行必要的初始化。# 这样,在类实例…...

fastzdp_sqlmodel新增get_first和is_exitsts方法
说明 经过fastzdp_login的整合,我们发现,fastzdp_sqlmodel还可以继续封装两个便捷的方法。 get_first:获取查询结果集中的第一条数据is_exitsts:判断数据是否已存在 封装get_first方法 def get_first(engine, model, query_di…...

嵌入式软件--数电基础 DAY 3
一、二进制 (1)文字表述 二进制数只能取0,1两个数字,逢二进一。 通过二进制表达文字。如战争时代的电报。 通过电灯泡的亮灭传递出信息。可以对灯亮和灯灭富裕一些含义,就能传达出想要的消息。 这就是编码和解码两…...

【生成式人工智能-十五-经典的影像生成方法-GAN】
经典的影像生成方法-GAN GANDiscriminatorGenerator还需要加入额外信息么 GAN可以加在其他模型上面我们可以用影像生成模型做什么? 前面讲过VAE和Flow-based以及diffusion Model ,今天讲最后一种经典的生成方法GAN。 GAN 前面讲的几种模型都是用加入额外…...

python 已知x+y=8 求x*y*(x-y)的最大值
先用导数求解 已知xy8 求xy(x-y)的最大值 令y8-x 则 f(x)x⋅(8−x)⋅(x−(8−x))x⋅(8−x)⋅(2x−8) 导数方程为 f(x)-3x^2 24x - 32 求方程 − 3 x 2 24 x − 32 0 -3x^2 24x - 32 0 −3x224x−320 的根。 首先,我们可以尝试对方程进行因式分解。观察…...

windows平台的postgresql主从数据库流备份
主: 操作系统:windows10 数据库版本:postgresql-16.2 ip:192.168.3.254 从: 操作系统:windows10 数据库版本:postgresql-16.2 ip:192.168.3.253 配置主库 配置 pg_hba.conf 文件 在 pg 的安装目录下,找到 …...
Spring 常见设计模式
什么是设计模式? 设计模式(Design pattern)是为解决软件设计中通用问题而被提出的一套指导性思想。它是一种被反复验证、经过实践证明并被广泛应用的代码设计经验和思想总结,可以帮助开发者通过一定的模式来快速的开发高质量、可维…...

优化大量数据导出到Excel的内存消耗(二):如果数据超出Excel单表上限,则进行分表
优化前:优化大量数据导出到Excel的内存消耗_大文件异步导出 内存占用高-CSDN博客 写Excel文件报错:Invalid row number (1048576) outside allowable range (0..1048575) 写入Excel时遇到IllegalArgumentException,原因是超出允许的最大行数…...
rustrover打开会报Error: Invalid toolchain
如果 cargo --version 正常输出,但在使用 RustRover 时出现“Invalid toolchain”错误,可能是由于 RustRover 工具链配置有问题或路径指向错误。 解决步骤: 1. 检查 RustRover 的工具链配置 打开 RustRover,进入 Preferences 或…...
docker-compose 安装canal
创建 Canal 配置文件 /conf/canal.properties mkdir -p conf/ touch /conf/canal.properties # canal.properties# tcp bind ip canal.ip 0.0.0.0 canal.port 11111 canal.metrics.pull.port 11112# zookeeper 集群配置 canal.zkServers canal.zookeeper.sessionTimeout…...

Unity动画模块 之 3D Rig页签
本文仅作笔记学习和分享,不用做任何商业用途本文包括但不限于unity官方手册,unity唐老狮等教程知识,如有不足还请斧正 1.Rig页签 Rig 选项卡 - Unity 手册,rig是设置骨骼与替身系统的,工作流程如下 Avatar是什么…...
【蓝桥杯冲刺省一,省一看这些就够了-Java版本】蓝桥杯日期问题相关模板以及练习题
蓝桥杯历年省赛真题 点击链接免费加入题单 日期问题 java.time Java 中用于处理日期和时间的主要类位于 java.time 包中。以下是一些常用的类和其功能的简要介绍: LocalDate:表示日期。它提供了获取年、月、日以及日期之间比较的方法。 LocalDate to…...

【经典算法】BFS_FloodFill算法
目录 1, 算法介绍2,算法原理和代码实现(含题目链接)733.图像渲染200.岛屿的数量695.岛屿的最大面积130.被围绕的区域 3, 算法总结 1, 算法介绍 FloodFill(洪水灌溉) 算法介绍: 假设一个 4 * 4 的方格代表一块土地&am…...

RocketMQ之Topic主题详解
Topic概念定义 主题:RocketMQ中消息传输和存储的顶层容器,用于标识同类业务中逻辑的消息,可理解为消息的分类,主题消息的分类取决于业务,要发送的业务消息最好单独是一个Topic主题,以保证互相不被干扰Topi…...

实战OpenCV之图像显示
基础入门 OpenCV提供的功能非常多,图像显示是最基础也是最直观的一部分。它让我们能够直观地看到算法处理后的效果,对于调试和验证都至关重要。在OpenCV中,图像显示主要依赖于以下四个关键的数据结构和函数。 1、Mat类。这是OpenCV中最基本的…...

I2C的10-bit地址空间
10-bit地址空间: I2C支持 10-bit的设备地址,此时的时序如下图所示: 在 10-bit地址的 I2C系统中,需要两个帧来传输 slave的地址。第一个帧的前 5个 bit固定为 b11110,后接 slave地址的高 2位,第 8位仍然是 …...

TinyWebserver的复现与改进(6):定时器处理非活动连接
如果客户端长时间没有动作,会占用了许多连接资源,严重影响服务器的性能。因此需要通过实现一个服务器定时器,处理这种非活跃连接,释放连接资源。 定时器处理流程 SIGALARM触发:整个流程开始于一个 SIGALARM 信号&…...

ThinkPHP5 5.0.23 远程代码执行漏洞
目录 1、启动环境 2、漏洞利用 3、更改传参方式 4、修改参数 5、发送数据 1、启动环境 docker-compose up -d 2、访问靶机ip端口号8080 2、漏洞利用 使用burpsuite抓包软件抓包 3、更改传参方式 将 GET传参改为POST传参 4、修改参数 url参数 /index.php?scaptcha post参…...
挑战杯推荐项目
“人工智能”创意赛 - 智能艺术创作助手:借助大模型技术,开发能根据用户输入的主题、风格等要求,生成绘画、音乐、文学作品等多种形式艺术创作灵感或初稿的应用,帮助艺术家和创意爱好者激发创意、提高创作效率。 - 个性化梦境…...

使用VSCode开发Django指南
使用VSCode开发Django指南 一、概述 Django 是一个高级 Python 框架,专为快速、安全和可扩展的 Web 开发而设计。Django 包含对 URL 路由、页面模板和数据处理的丰富支持。 本文将创建一个简单的 Django 应用,其中包含三个使用通用基本模板的页面。在此…...

Spark 之 入门讲解详细版(1)
1、简介 1.1 Spark简介 Spark是加州大学伯克利分校AMP实验室(Algorithms, Machines, and People Lab)开发通用内存并行计算框架。Spark在2013年6月进入Apache成为孵化项目,8个月后成为Apache顶级项目,速度之快足见过人之处&…...
MySQL 隔离级别:脏读、幻读及不可重复读的原理与示例
一、MySQL 隔离级别 MySQL 提供了四种隔离级别,用于控制事务之间的并发访问以及数据的可见性,不同隔离级别对脏读、幻读、不可重复读这几种并发数据问题有着不同的处理方式,具体如下: 隔离级别脏读不可重复读幻读性能特点及锁机制读未提交(READ UNCOMMITTED)允许出现允许…...

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实现分布式…...
在rocky linux 9.5上在线安装 docker
前面是指南,后面是日志 sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo dnf install docker-ce docker-ce-cli containerd.io -y docker version sudo systemctl start docker sudo systemctl status docker …...
深入浅出:JavaScript 中的 `window.crypto.getRandomValues()` 方法
深入浅出:JavaScript 中的 window.crypto.getRandomValues() 方法 在现代 Web 开发中,随机数的生成看似简单,却隐藏着许多玄机。无论是生成密码、加密密钥,还是创建安全令牌,随机数的质量直接关系到系统的安全性。Jav…...

理解 MCP 工作流:使用 Ollama 和 LangChain 构建本地 MCP 客户端
🌟 什么是 MCP? 模型控制协议 (MCP) 是一种创新的协议,旨在无缝连接 AI 模型与应用程序。 MCP 是一个开源协议,它标准化了我们的 LLM 应用程序连接所需工具和数据源并与之协作的方式。 可以把它想象成你的 AI 模型 和想要使用它…...
Leetcode 3577. Count the Number of Computer Unlocking Permutations
Leetcode 3577. Count the Number of Computer Unlocking Permutations 1. 解题思路2. 代码实现 题目链接:3577. Count the Number of Computer Unlocking Permutations 1. 解题思路 这一题其实就是一个脑筋急转弯,要想要能够将所有的电脑解锁&#x…...

学习STC51单片机31(芯片为STC89C52RCRC)OLED显示屏1
每日一言 生活的美好,总是藏在那些你咬牙坚持的日子里。 硬件:OLED 以后要用到OLED的时候找到这个文件 OLED的设备地址 SSD1306"SSD" 是品牌缩写,"1306" 是产品编号。 驱动 OLED 屏幕的 IIC 总线数据传输格式 示意图 …...