【低照度图像增强系列(8)】URetinex-Net算法详解与代码实现(2022|CVPR)

news2024/9/22 5:34:07

前言 

☀️ 在低照度场景下进行目标检测任务,常存在图像RGB特征信息少提取特征困难目标识别和定位精度低等问题,给检测带来一定的难度。

     🌻使用图像增强模块对原始图像进行画质提升,恢复各类图像信息,再使用目标检测网络对增强图像进行特定目标检测,有效提高检测的精确度。

      ⭐本专栏会介绍传统方法、Retinex、EnlightenGAN、SCI、Zero-DCE、IceNet、RRDNet、URetinex-Net等低照度图像增强算法。

👑完整代码已打包上传至资源→低照度图像增强代码汇总资源

目录

前言 

🚀一、URetinex-Net介绍

☀️1.1 URetinex-Net简介   

☀️1.2 URetinex-Net的网络结构  

(1)初始化模块

(2)展开优化模块

(3)照度调整模块

🚀二、URetinex-Net核心代码 

☀️2.1 architecture.py

☀️2.2 decom.py

☀️2.3 illumination_adjustment.py

☀️2.4 illumination_enhance.py

☀️2.5 Math_Module.py

☀️2.6 restoration.py

☀️2.7 evaluate.py

🚀三、URetinex-Net代码复现 

☀️3.1 环境配置

☀️3.2 运行过程 

☀️3.3 运行效果

🚀一、URetinex-Net介绍

学习资料:

  • 论文题目:《URetinex-Net: Retinex-based Deep Unfolding Network for Low-light Image Enhancement》(URetinex-Net:基于Retinex的低光图像增强深度展开网络)
  • 论文解读:CVPR|《URetinex-Net: Retinex-based Deep Unfolding Network for Low-light Image Enhance》论文超详细解读(翻译+精读)
  • 原文地址:Wu_URetinex-Net_Retinex-Based_Deep_Unfolding_Network_for_Low-Light_Image_Enhancement_CVPR_2022_paper.pdf
  • 源码地址:GitHub - AndersonYong/URetinex-Net: Code Released for URetinex-Net

☀️1.1 URetinex-Net简介   

这是深圳大学、香港城市大学和南洋理工大学发表在CVPR2022的一篇暗图增强的论文。

URetinex-Net借鉴了Retinex模型,该模型基于人眼对亮度感知的理论,旨在分离图像中的色彩和光照信息

通过将分解问题公式化为隐式先验正则化模型,设计了三个基于学习的模块:

  • 数据依赖初始化:一个模块负责根据数据进行初始化。 
  • 高效展开优化:引入两个网络,以数据驱动方式自适应地拟合隐式先验,实现噪声抑制和细节保留。 
  • 用户指定的照明增强:一个模块负责用户指定的照明增强。 

特别地,所提出的展开优化模块通过引入两个网络,以数据驱动的方式自适应拟合隐式先验,实现了最终分解结果的噪声抑制和细节保留。

通过深度学习的手段,该项目提出了一种深度展开网络,能够更精确地估计图像的亮度分布,从而在提升图像亮度的同时保留原有的色彩信息和细节。


☀️1.2 URetinex-Net的网络结构  

(1)初始化模块

本文提出一个使用全卷积网络的初始化模块D,自适应学习R0和L0。

组成:初始化模块由三个 Conv+LeakyReLU 层组成,后面是卷积层和 ReLU 层。

整个卷积层的内核大小设置为3*3

损失函数设计:

第一项是重建损失,第二项是结构保留损失,鼓励初始化照明保留图像整体结构。

效果:

图3:低光图像中一个 patch 的统计特征,显然,刚性初始化(b)改变了原始弱光图像三个通道 {R,G,B} 的强度统计特性,而在本文的初始化模块(c)中得到很好的保留。


(2)展开优化模块

模块目标:

展开优化模块通过迭代解决四个单变量子问题,在T次迭代中更新变量。

P的更新规则:

P子问题是经典最小二乘问题,通过求导得到闭式解,更新公式基于初始反射。

Q的更新规则:

Q的更新可以通过求解方程中的Q子问题来完成,由于RGB通道共享同一灰度照明层,更新公式基于初始照明。

L的更新规则:

对于L和R子问题,不再手工设计先验,而是采用基于学习的方法探索隐式先验。 引入两个网络GL和GR分别更新L和R。

R的更新规则:

用GR表示,输入为Pk和Qk,θR为可学习参数。

使用压缩和激励(SE)块融合Pk和Qk以更新Rk。


(3)照度调整模块

模块目标:增加图像增强的真实光照水平,需要灵活调整以适应不同需求。

结构:初始化模块由三个 Conv+LeakyReLU 层组成,后面是卷积层和 ReLU 层。

整个卷积层的内核大小设置为5*5。

学习方式的照明调整:

本文提出一个照明调整模块,以低光照照明 L 和用户指定的增强比率 ω 作为输入,表示为

损失函数:

包含梯度一致性损失、重构损失和结构相似性损失,以确保调整后的照明图保持与原图的一致性并能重建正常光照图像。


🚀二、URetinex-Net核心代码 

这一节主要介绍 architecture.py、decom.py、illumination_adjustment.py、illumination_enhance.py、Math_Module.py、restoration.py、evaluate.py


☀️2.1 architecture.py

import torch
import torch.nn as nn
import torchvision

#--------------------------------1.批归一化层---------------------------------------------#
def get_batchnorm_layer(opts):
    if opts.norm_layer == "batch":
        norm_layer = nn.BatchNorm2d # 批归一化层
    elif opts.layer == "spectral_instance":
        norm_layer = nn.InstanceNorm2d # 实例归一化层
    else:
        print("not implemented")
        exit()
    return norm_layer

#--------------------------------2.卷积层---------------------------------------------#
def get_conv2d_layer(in_c, out_c, k, s, p=0, dilation=1, groups=1):
    '''
    in_c:输入通道数。
    out_c:输出通道数。
    k:卷积核大小。
    s:步幅。
    p:填充(默认值为0)。
    dilation:卷积核扩展(默认值为1)。
    groups:分组卷积(默认值为1)。
    '''
    return nn.Conv2d(in_channels=in_c,
                    out_channels=out_c,
                    kernel_size=k,
                    stride=s,
                    padding=p,dilation=dilation, groups=groups)

#--------------------------------3.反卷积层---------------------------------------------#
def get_deconv2d_layer(in_c, out_c, k=1, s=1, p=1):
    return nn.Sequential(
        nn.Upsample(scale_factor=2, mode="bilinear"), # 进行双线性插值,将输入的特征图上采样2倍。
        nn.Conv2d(
            in_channels=in_c,
            out_channels=out_c,
            kernel_size=k,
            stride=s,
            padding=p
        )
    )

#--------------------------------4.恒等映射层---------------------------------------------#
class Identity(nn.Module):

    def __init__(self):
        super(Identity, self).__init__()

    def forward(self, x):
        return x

这段代码主要就是实现的一些基本的神经网络层的定义和操作


☀️2.2 decom.py

import torch
import torch.nn as nn
from network.architecture import *

class Decom(nn.Module):
    def __init__(self):
        super().__init__()
        self.decom = nn.Sequential(
        '''  
            in_c=3: 表示输入通道数为3。
            out_c = 32: 表示输出通道数为32。
            k = 3: 表示卷积核的尺寸为3x3。
            s = 1: 表示步幅为1。
            p = 1: 表示填充为1
        '''
            get_conv2d_layer(in_c=3, out_c=32, k=3, s=1, p=1),
            nn.LeakyReLU(0.2, inplace=True),
            get_conv2d_layer(in_c=32, out_c=32, k=3, s=1, p=1),
            nn.LeakyReLU(0.2, inplace=True),
            get_conv2d_layer(in_c=32, out_c=32, k=3, s=1, p=1),
            nn.LeakyReLU(0.2, inplace=True),
            get_conv2d_layer(in_c=32, out_c=4, k=3, s=1, p=1),
            nn.ReLU()
        )

    def forward(self, input):
        output = self.decom(input)
        R = output[:, 0:3, :, :]
        L = output[:, 3:4, :, :]
        return R, L

这段代码主要就是用于将输入图像分解为反射分量和照明分量

通过多个卷积层和激活函数,模型逐步提取特征,最后输出四个通道,其中前三个通道表示反射分量,最后一个通道表示照明分量。


☀️2.3 illumination_adjustment.py

import torch
import numpy as np
import torch.nn as nn
from network.architecture import get_conv2d_layer
import torch.nn.functional as F

class Adjust_naive(nn.Module):
    def __init__(self, opt):
        super().__init__()
        self.conv1 = get_conv2d_layer(in_c=2, out_c=32, k=5, s=1, p=2)
        self.conv2 = get_conv2d_layer(in_c=32, out_c=32, k=5, s=1, p=2)
        self.conv3 = get_conv2d_layer(in_c=32, out_c=32, k=5, s=1, p=2)
        self.conv4 = get_conv2d_layer(in_c=32, out_c=1, k=5, s=1, p=2)
        self.leaky_relu = nn.LeakyReLU(0.2)
        self.relu = nn.ReLU()
        '''
        卷积层定义:
           conv1: 输入通道数为2,输出通道数为32,卷积核大小为5x5,步幅为1,填充为2。
           conv2 和 conv3: 输入和输出通道数为32,其他参数与 conv1 相同。
           conv4: 输入通道数为32,输出通道数为1,其他参数与 conv1 相同。
        激活函数:
           leaky_relu: LeakyReLU 激活函数,负斜率为0.2。
           relu: ReLU 激活函数。
        '''
    def forward(self, l, alpha):
        input = torch.cat([l, alpha], dim=1)
        x = self.conv1(input)            
        x = self.conv2(self.leaky_relu(x))   
        x = self.conv3(self.leaky_relu(x))   
        x = self.conv4(self.leaky_relu(x))
        x = self.relu(x) 
        return x

这段代码主要就是用于图像处理任务,包含调整图像的亮度或其他特定特征。


☀️2.4 illumination_enhance.py

import torch.nn as nn
import torch
import math
from network.architecture import get_batchnorm_layer, get_conv2d_layer

class Illumination_Alone(nn.Module):
    def __init__(self, opts):
        super().__init__()
        self.opts = opts
        self.conv1 = get_conv2d_layer(in_c=1, out_c=32, k=5, s=1, p=2)
        self.conv2 = get_conv2d_layer(in_c=32, out_c=32, k=5, s=1, p=2)
        self.conv3 = get_conv2d_layer(in_c=32, out_c=32, k=5, s=1, p=2)
        self.conv4 = get_conv2d_layer(in_c=32, out_c=32, k=5, s=1, p=2)
        self.conv5 = get_conv2d_layer(in_c=32, out_c=1, k=1, s=1, p=0)
        '''
           卷积层定义:
              conv1: 输入通道数为1,输出通道数为32,卷积核大小为5x5,步幅为1,填充为2。
              conv2, conv3, conv4: 输入和输出通道数均为32,其他参数与 conv1 相同。
              conv5: 输入通道数为32,输出通道数为1,卷积核大小为1x1,步幅为1,无填充。
        '''
        self.leaky_relu_1 = nn.LeakyReLU(0.2, inplace=True)
        self.leaky_relu_2 = nn.LeakyReLU(0.2, inplace=True)
        self.leaky_relu_3 = nn.LeakyReLU(0.2, inplace=True)
        self.leaky_relu_4 = nn.LeakyReLU(0.2, inplace=True)
        self.relu = nn.ReLU()
        #self.sigmoid = nn.Sigmoid()
        '''
           激活函数:
               leaky_relu_1 到 leaky_relu_4: LeakyReLU 激活函数,负斜率为0.2,inplace=True 表示直接在输入上进行操作,节省内存。
               relu: ReLU 激活函数。
        '''
    
    def forward(self, l):
        x = l
        x1 = self.leaky_relu_1(self.conv1(x))
        x2 = self.leaky_relu_2(self.conv2(x1))
        x3 = self.leaky_relu_3(self.conv3(x2))
        x4 = self.leaky_relu_4(self.conv4(x3))
        x5 = self.relu(self.conv5(x4))
        return x5

这段代码主要是定义了Illumination_Alone 这个类,主要用于处理图像照明分量的卷积神经网络。


☀️2.5 Math_Module.py

import torch
import torch.nn as nn
from torchvision.transforms import Grayscale


class P(nn.Module):
    """
        to solve min(P) = ||I-PQ||^2 + γ||P-R||^2
        this is a least square problem
        how to solve?
        P* = (gamma*R + I*Q) / (Q*Q + gamma)
    """
    def __init__(self):
        super().__init__()

    def forward(self, I, Q, R, gamma):
        return ((I * Q + gamma * R) / (gamma + Q * Q))
        '''
           I: 输入图像或特征图。
           Q: 一个特征图或滤波器。
           R: 参考图像或特征图。
           gamma: 正则化参数。
        '''
class Q(nn.Module):
    """
        to solve min(Q) = ||I-PQ||^2 + λ||Q-L||^2
        Q* = (lamda*L + I*P) / (P*P + lamda)
    """
    def __init__(self):
        super().__init__()
    
    def forward(self, I, P, L, lamda):
        '''
           I: 输入图像或特征图。
           P: 一个特征图或滤波器。
           L: 参考图像或特征图。
           lamda: 正则化参数。
        '''
        # 将 I 和 P 分别分成红、绿、蓝三个通道。
        IR = I[:, 0:1, :, :]
        IG = I[:, 1:2, :, :]
        IB = I[:, 2:3, :, :]

        PR = P[:, 0:1, :, :]
        PG = P[:, 1:2, :, :]
        PB = P[:, 2:3, :, :]

        return (IR*PR + IG*PG + IB*PB + lamda*L) / ((PR*PR + PG*PG + PB*PB) + lamda)

这段代码主要就是展开模块那一部分的计算规则。


☀️2.6 restoration.py

import torch.nn as nn
import torch
from torch.nn.modules.linear import Identity
from network.architecture import *
import math
import torch.nn.functional as F

class HalfDnCNNSE(nn.Module):
    def __init__(self, opts):
        super().__init__()
        self.opts = opts
        
        if self.opts.concat_L:  # 一个布尔值,决定是否将 l 输入拼接到 r 输入
            self.conv1 = get_conv2d_layer(in_c=3, out_c=32, k=3, s=1, p=1) # 根据 self.opts.concat_L,设置不同的卷积层。
            self.relu1 = nn.ReLU(inplace=True)
            self.conv2 = get_conv2d_layer(in_c=1, out_c=32, k=3, s=1, p=1)
            self.relu2 = nn.ReLU(inplace=True)
        else:
            self.conv1 = self.conv1 = get_conv2d_layer(in_c=3, out_c=64, k=3, s=1, p=1)
            self.relu1 = nn.ReLU(inplace=True)
        self.se_layer = SELayer(channel=64)  # 引入 SE 层来提升通道间的特征表示能力。
        self.conv3 = get_conv2d_layer(in_c=64, out_c=64, k=3, s=1, p=1)
        self.relu3 = nn.ReLU(inplace=True)
        self.conv4 = get_conv2d_layer(in_c=64, out_c=64, k=3, s=1, p=1)
        self.relu4 = nn.ReLU(inplace=True)
        self.conv5 = get_conv2d_layer(in_c=64, out_c=64, k=3, s=1, p=1)
        self.relu5 = nn.ReLU(inplace=True)
        self.conv6 = get_conv2d_layer(in_c=64, out_c=64, k=3, s=1, p=1)
        self.relu6 = nn.ReLU(inplace=True)
        self.conv7 = get_conv2d_layer(in_c=64, out_c=64, k=3, s=1, p=1)
        self.relu7 = nn.ReLU(inplace=True)

        self.conv8 = get_conv2d_layer(in_c=64, out_c=3, k=3, s=1, p=1)  # 将特征图还原到3个通道。

    def forward(self, r, l):
        if self.opts.concat_L:  # 如果 self.opts.concat_L 为真,则分别处理 r 和 l,然后将它们拼接。
            r_fs = self.relu1(self.conv1(r))
            l_fs = self.relu2(self.conv2(l))
            inf = torch.cat([r_fs, l_fs], dim=1)  # 将拼接后的特征或仅 r 的特征输入到 SE 层。
            se_inf = self.se_layer(inf)  # 最后一层卷积输出 n,然后将 n 加到 r 上,得到最终的恢复图像 r_restore。
        else:
            r_fs = self.relu1(self.conv1(r))
            se_inf = self.se_layer(r_fs)
        x1 = self.relu3(self.conv3(se_inf))
        x2 = self.relu4(self.conv4(x1))
        x3 = self.relu5(self.conv5(x2))
        x4 = self.relu6(self.conv6(x3))
        x5 = self.relu7(self.conv7(x4))
        n = self.conv8(x5)
        r_restore = r + n  # 最后一层卷积输出 n,然后将 n 加到 r 上,得到最终的恢复图像 r_restore。
        return r_restore

class SELayer(nn.Module):
    def __init__(self, channel, reduction=16):  # reduction: 降维因子,用于减少通道数。

        super(SELayer, self).__init__()
        self.avg_pool = nn.AdaptiveAvgPool2d(1)
        self.fc = nn.Sequential(
            nn.Linear(channel, channel // reduction, bias=False),
            nn.ReLU(inplace=True),
            nn.Linear(channel // reduction, channel, bias=False),
            nn.Sigmoid()
        )

    def forward(self, x):
        b, c, _, _ = x.size()
        y = self.avg_pool(x).view(b, c)
        y = self.fc(y).view(b, c, 1, 1)
        return x * y.expand_as(x)

这段代码主要就是定义了HalfDnCNNSE这个类,实现了一个包含通道注意力机制的卷积神经网络,旨在增强图像特征表示


☀️2.7 evaluate.py

import argparse
from fileinput import filename
from locale import locale_encoding_alias
import torch
import torch.nn as nn
from network.Math_Module import P, Q
from network.decom import Decom
import os
import torchvision
import torchvision.transforms as transforms
from PIL import Image
import time
from utils import *
import glob
'''
各个包的作用:
  argparse:用于解析命令行参数。
  torch 和 torch.nn : PyTorch 的核心模块。
  从 network.Math_Module 中导入了 P 和 Q 模块,用于计算。
  从 network.decom 中导入了 Decom 模块,用于图像分解。
  os :用于操作系统接口。
  torchvision 和 PIL :用于图像处理和变换。
  time :用于计时。
  utils 和 glob :用于工具函数和文件操作。
'''

"""
  As different illumination adjustment ratio will cause
different enhanced results. Certainly you can tune the ratio youself
to get the best results.
  To get better result, we use the illumination of normal light image 
to adaptively generate ratio.
  Noted that KinD and KinD++ also use ratio to guide the illumination adjustment,
for fair comparison, the ratio of their methods also generate by the illumination
of normal light image.
"""

def one2three(x):  # one2three函数将单通道的张量复制三次,生成三通道的张量。
    return torch.cat([x, x, x], dim=1).to(x)

class Inference(nn.Module):
    def __init__(self, opts):
        super().__init__()
        self.opts = opts
        # loading decomposition model 
        self.model_Decom_low = Decom()
        self.model_Decom_high = Decom()
        self.model_Decom_low = load_initialize(self.model_Decom_low, self.opts.Decom_model_low_path)
        self.model_Decom_high = load_initialize(self.model_Decom_high, self.opts.Decom_model_high_path)
        # loading R; old_model_opts; and L model
        self.unfolding_opts, self.model_R, self.model_L= load_unfolding(self.opts.unfolding_model_path)
        # loading adjustment model
        self.adjust_model = load_adjustment(self.opts.adjust_model_path)
        self.P = P()
        self.Q = Q()
        transform = [
            transforms.ToTensor(),
        ]
        self.transform = transforms.Compose(transform)  # 使用 transforms.Compose 定义图像预处理方法,将图像转换为张量。
        print(self.model_Decom_low)
        print(self.model_R)
        print(self.model_L)
        print(self.adjust_model)
        #time.sleep(8)
        
    def get_ratio(self, high_l, low_l):  # 计算高低光照图像的比率,用于后续的光照调整。
        ratio = (low_l / (high_l + 0.0001)).mean()
        low_ratio = torch.ones(high_l.shape).cuda() * (1/(ratio+0.0001))  # 防止除以零,添加了一个小常数 0.0001。
        return low_ratio

    def unfolding(self, input_low_img):
        for t in range(self.unfolding_opts.round):  # 展开函数对低光照图像进行多轮处理,初始时生成 P 和 Q,然后逐步更新。
            if t == 0: # initialize R0, L0
                P, Q = self.model_Decom_low(input_low_img)
            else: # update P and Q # 使用了 P 和 Q 模块进行更新。
                w_p = (self.unfolding_opts.gamma + self.unfolding_opts.Roffset * t)
                w_q = (self.unfolding_opts.lamda + self.unfolding_opts.Loffset * t)
                P = self.P(I=input_low_img, Q=Q, R=R, gamma=w_p)
                Q = self.Q(I=input_low_img, P=P, L=L, lamda=w_q) 
            R = self.model_R(r=P, l=Q) # 返回反射分量 R
            L = self.model_L(l=Q)# 返回光照分量 L
        return R, L
    
    def lllumination_adjust(self, L, ratio):
        ratio = torch.ones(L.shape).cuda() * ratio
        return self.adjust_model(l=L, alpha=ratio)
    
    def forward(self, input_low_img, input_high_img): # 前向传播函数接收低光照图像和高光照图像作为输入。
        if torch.cuda.is_available(): # 将图像移动到 GPU(如果可用)。
            input_low_img = input_low_img.cuda()
            input_high_img = input_high_img.cuda()
        with torch.no_grad():
            start = time.time()   # 在不计算梯度的情况下,进行图像增强处理,计算反射分量 R 和光照分量 L。
            R, L = self.unfolding(input_low_img)
            # the ratio is calculated using the decomposed normal illumination
            _, high_L = self.model_Decom_high(input_high_img)
            ratio = self.get_ratio(high_L, L) # 计算高光照图像的光照分量 high_L,得到调整比率 ratio。
            High_L = self.lllumination_adjust(L, ratio)
            I_enhance = High_L * R # 调整光照分量并生成增强后的图像 I_enhance。
            p_time = (time.time() - start) # 返回增强后的图像和处理时间。
        return I_enhance, p_time

    def evaluate(self): # evaluate 函数遍历低光照图像目录中的所有图像文件
        low_files = glob.glob(self.opts.low_dir+"/*.png")
        for file in low_files:
            file_name = os.path.basename(file)
            name = file_name.split('.')[0]
            high_file = os.path.join(self.opts.high_dir, file_name)
            low_img = self.transform(Image.open(file)).unsqueeze(0)
            high_img = self.transform(Image.open(high_file)).unsqueeze(0)
            enhance, p_time = self.forward(low_img, high_img)
            if not os.path.exists(self.opts.output):
                os.makedirs(self.opts.output)
            save_path = os.path.join(self.opts.output, file_name.replace(name, "%s_URetinexNet"%(name)))
            np_save_TensorImg(enhance, save_path)  
            print("================================= time for %s: %f============================"%(file_name, p_time))



    
if __name__ == "__main__":
    parser = argparse.ArgumentParser(description='Configure')
    # specify your data path here!
    parser.add_argument('--low_dir', type=str, default="E:/RetinexNet_PyTorch-master/data/train/low")
    parser.add_argument('--high_dir', type=str, default="E:/RetinexNet_PyTorch-master/data/train/high")
    parser.add_argument('--output', type=str, default="./demo/output/LOL")
    # ratio are recommended to be 3-5, bigger ratio will lead to over-exposure 
    # model path
    parser.add_argument('--Decom_model_low_path', type=str, default="./ckpt/init_low.pth")
    parser.add_argument('--Decom_model_high_path', type=str, default="./ckpt/init_high.pth")
    parser.add_argument('--unfolding_model_path', type=str, default="./ckpt/unfolding.pth")
    parser.add_argument('--adjust_model_path', type=str, default="./ckpt/L_adjust.pth")
    parser.add_argument('--gpu_id', type=int, default=0)
    
    opts = parser.parse_args()
    for k, v in vars(opts).items():
        print(k, v)
    
    os.environ['CUDA_VISIBLE_DEVICES'] = str(opts.gpu_id)
    model = Inference(opts).cuda()
    model.evaluate()

这段代码主要就是实现了一个完整的低光照图像增强流程。通过加载不同的模型,对输入的低光照图像进行分解、比率计算、光照调整,最终生成增强后的图像并保存。 


🚀三、URetinex-Net代码复现 

☀️3.1 环境配置

  1. Python == 3.7.6
  2. PyTorch == 1.4.0
  3. torchvision == 0.5.0

☀️3.2 运行过程 

 暗光增强——URetinex-Net网络推理测试(详细图文教程)-CSDN博客

参考这篇文章。


☀️3.3 运行效果

 

美丽的凌水湖~ 

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

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

相关文章

手机也能玩转AI影像?荣耀200系列带来手机人像摄影新升级

智能手机在影像技术上的革新从未停歇,荣耀200系列系统的全新升级,为用户带来了更加丰富和便捷的拍摄体验。AI技术的融入,让摄影变得更加智能,简化了编辑过程,使得每个用户都能成为专业的摄影师。 一、AI消除功能&#…

差旅费控平台选型抓住这五点,选的好用的才舒心!

市场竞争从增量机会转为存量博弈,起决定作用的是造就和增强公司的核心竞争力,以精细化管理做足降本增效的“基本功”成为众多企业谋划发展的关键词。 当下企业差旅服务已经初步完成数字化升级,线上预订,灵活支付,统一结…

Linux系统编程-进程间通信(IPC)常用方式详解

进程间通信(IPC,Inter-Process Communication)是指在操作系统中,不同进程之间进行数据交换和信息传递的机制。这种通信允许正在运行的多个进程能够相互协作、共享数据或者进行同步操作,以实现更复杂的任务和功能。Linu…

国外UI设计赏析—汽车行业

国外汽车网页设计界面往往展现出几个显著的优点,这些优点不仅提升了用户体验,还增强了品牌形象与产品吸引力。首先,它们注重界面设计的直观性与互动性,通过高清大图、动态效果以及简洁明了的布局,让用户能够一目了然地…

王老师 linux c++ 通信架构 笔记(一)linux虚拟机的安装

(0)本门课程会涉及很多知识。在此集中记录,做笔记,也可能加入别的专栏。 (1) vmware 15 的下载和密钥上网查找。 ubuntu - 16 - 04 的版本才 800 M ,来 csdn 找镜像 下载。 (2&#…

动态sql 单选变多选

实体类 添加数组存储值 private ArrayList tssjfjList; <!-- <if test"tssjfj ! null and tssjfj ! ">and tssjfj #{tssjfj}</if>--><if test"tssjfjList ! null and tssjfjList.size() > 0">AND tssjfj IN<fo…

《昇思25天学习打卡营第20天|Diffusion扩散模型》

#学习打卡第20天# Diffusion扩散模型 本文的介绍是基于denoising diffusion probabilistic model &#xff08;DDPM&#xff09;&#xff0c;DDPM已经在&#xff08;无&#xff09;条件图像/音频/视频生成领域取得了较多显著的成果&#xff0c;现有的比较受欢迎的的例子包括由O…

2024年,搞AI就别卷模型了

你好&#xff0c;我是三桥君 2022年11月30日&#xff0c;OpenAI发布了一款全新的对话式通用人工智能工具——ChatGPT。 该工具发布后&#xff0c;仅用5天时间就吸引了100万活跃用户&#xff0c;而在短短2个月内&#xff0c;其活跃用户数更是飙升至1亿&#xff0c;成为历史上增…

牛顿黏滞定律

牛顿黏滞定律描述了流体内部的剪切应力与速度梯度之间的关系。公式如下&#xff1a; τ η d v x d y \tau \eta \frac{dv_x}{dy} τηdydvx​​ 其中&#xff1a; τ \tau τ 是剪切应力&#xff08;shear stress&#xff09;&#xff0c;单位是帕斯卡&#xff08;Pa&…

互信息(Mutual Information,MI)的原理和计算

互信息&#xff08;Mutual Information&#xff0c;MI&#xff09;是信息论中的一个度量&#xff0c;用于量化两个随机变量之间的依赖关系。互信息度量了一个随机变量包含了关于另一个随机变量的信息量。它可以用来识别和量化两个信号之间的非线性相关性。互信息可以揭示两个信…

Web开发:一个可拖拽的模态框(HTML、CSS、JavaScript)

目录 一、需求描述 二、实现效果 三、完整代码 四、实现过程 1、HTML 页面结构 2、CSS 元素样式 3、JavaScript动态控制 &#xff08;1&#xff09;获取元素 &#xff08;2&#xff09;显示\隐藏遮罩层与模态框 &#xff08;3&#xff09;实现模态框拖动效果 一、需求…

【离线查询 堆 优先队列】1383. 最大的团队表现值

本文涉及知识点 离线查询 堆 优先队列 算法与数据结构汇总 LeetCode1383. 最大的团队表现值 给定两个整数 n 和 k&#xff0c;以及两个长度为 n 的整数数组 speed 和 efficiency。现有 n 名工程师&#xff0c;编号从 1 到 n。其中 speed[i] 和 efficiency[i] 分别代表第 i 位…

开源项目的认识理解

目录 开源项目有哪些机遇与挑战&#xff1f; 1.开源项目的发展趋势 2.开源的经验分享&#xff08;向大佬请教与上网查询&#xff09; 3.开源项目的挑战 开源项目有哪些机遇与挑战&#xff1f; 1.开源项目的发展趋势 1. 持续增长与普及 - 开源项目将继续增长&#xff0c…

软件测试——AI快速入门

工作职责&#xff1a; 1.负责产品系统测试&#xff0c;包括功能测试、性能测试、稳定性测试、用户场景测试、可靠性测试等。 2.负责测试相关文档的编写&#xff0c;包括测试计划、测试用例、测试报告等。 3.负责自动化测试框架、用例的维护。 岗位要求&#xff1a; 1.熟练…

编程范式之并发编程

目录 前言1. 并发编程的定义2. 并发编程的特点2.1 任务交替执行2.2 状态共享与同步2.3 并行执行 3. 并发编程的适用场景3.1 高性能计算3.2 I/O 密集型应用3.3 实时系统 4. 并发编程的优点4.1 提高资源利用率4.2 缩短响应时间4.3 提高系统吞吐量 5. 并发编程的缺点5.1 编程复杂性…

MP4怎么转为MP3?超多人都在用的四种转换方法!

MP4怎么转为MP3&#xff1f;MP4&#xff0c;这一风靡全球的多媒体容器格式&#xff0c;无疑是数字时代的一枚璀璨明珠&#xff0c;深深烙印在每个人的数字生活之中&#xff0c;那么&#xff0c;它究竟是如何在众多格式中脱颖而出&#xff0c;赢得如此广泛认可的呢&#xff1f;首…

【Redis】初识 Redis

文章目录 1 什么是 Redis2 Redis 的特点2.1 速度快2.2 可编程性2.3 可拓展性2.4 持久化2.5 主从复制2.5 高可用和分布式2.6 客户端语言多 3 Redis 使用场景3.1 实时数据存储3.2 缓存和 Session 存储3.3 消息队列 4 Redis 重大版本5 CentOS7 安装 Redis5 1 什么是 Redis Redis …

【typedb】例子:药物发现 1: 模式导入

typedb-examples/drug-discovery/ Drug discovery监听0.0.0.0:1729 但这么连接肯定不行: localhost:1729 可以: 一直无法点击schema图标:先创建一个数据库 选中数据库: 选中后就可以了:

分布式存储快速入门HDFS

分布式存储快速入门 文章目录 分布式存储快速入门一、概要介绍1.1 什么是分布式存储1.2 分布式存储的重要性和应用场景 二、HDFS基础2.1 HDFS的起源和发展2.2 HDFS的架构2.3 HDFS的基本概念2.4 HDFS的特性2.5 HDFS的版权 三、HDFS安装与配置3.1 环境准备3.2 安装Hadoop和配置HD…

你也想做一个Element-ui吧!!!——Blueの前端路(一)

目录 前言&#xff1a; 父子组件 button组件 使用vue脚手架初始化一个项目 如何封装&#xff0c;注册和使用一个组件 main.js中将组件设置为全局 使用 此组件我们所需实现的内容 type 父组件组件传递type属性 子组件接收负组件传递的数据 通过绑定类名的方法动态控制…