【论文阅读笔记】IceNet算法与代码 | 低照度图像增强 | IEEE | 2021.12.25
目录
1 导言
2 相关工作
A 传统方法
B 基于CNN的方法
C 交互方式
3 算法
A 交互对比度增强
1)Gamma estimation
2)颜色恢复
3)个性化初始η
B 损失函数
1)交互式亮度控制损失
2)熵损失
3)平滑损失
4)总损失
C 实现细节
4 实验
5 IceNet环境配置和运行
1 下载代码
2 运行
3 训练
💚论文题目:IceNet for Interactive Contrast Enhancement
💜论文地址:https://export.arxiv.org/pdf/2109.05838v2.pdf
💙代码地址:https://github.com/keunsoo-ko/IceNet
【摘要】本文提出了一种基于CNN的交互式对比度增强(contrast enhancement)算法IceNet,使得用户可以根据自己的喜好轻松地调整图像对比度。具体来说,用户提供一个参数来控制全局亮度和两种类型的涂鸦来使图像中的局部区域变暗或变亮。然后,给定这些注释,IceNet估计一个伽马图,用于逐像素的伽马校正。最后,通过颜色恢复,得到增强后的图像。用户可以迭代地提供注释,以获得满意的图像。IceNet还可以自动生成个性化的增强图像,如果需要,可以作为进一步调整的基础。此外,为了有效且可靠地训练IceNet,我们提出了三种可微的损失函数。大量实验表明,IceNet可以为用户提供令人满意的增强图像。
索引词:交互式对比度增强、个性化对比度增强、卷积神经网络、自适应伽马校正。
1 导言
🦋🦋🦋尽管近年来成像技术取得了很大的进步,但由于曝光不均匀、快门周期短、环境光弱等因素的影响,照片往往不能忠实地再现场景细节。这类照片表现出对比度失真、色彩褪色、强度低等现象;特别是,异常的光照条件会显著地扭曲颜色、纹理和物体,从而降低视觉体验。对比增强( CE )技术可以缓解这些问题。
🦋🦋🦋为了开发有效的CE技术,人们进行了许多尝试。一种简单而有效的方法是从输入到输出像素值的转换函数使用参数曲线。例如,一种权力法则是伽马校正中著名的参数曲线。这些参数曲线产生了很有前途的结果,但找到可靠的参数是很有挑战性的,这些参数对不同的图像都是有效的。最近,随着卷积神经网络( CNN )在低级视觉领域的成功,基于CNN的CE方法也被提出,并取得了出色的性能。
🦋🦋🦋为了实现CE的自动化,人们进行了大量的研究。然而,CE是一个主观的过程,因为人们对对比度有不同的偏好。值得注意的是,对比度在图像解读中发挥着不同的作用。例如,观看者使用对比来吸引注意力;艺术家通过对比传达强调;平面设计师通过对比来告诉眼睛该往何处去。因此,增强对比度没有唯一确定的方法。图1说明了可以有多种方法来增强同一幅图像的对比度。专业软件,如Photoshop,提供了许多根据个人喜好调整对比度的工具,但使用这些工具需要花费很多精力。在本文中,我们提出了第一个基于CNN的交互式CE算法,使用户能够方便地自适应地调整图像对比度。
图1。使用IceNet对同一幅图像进行四种不同的CE结果。
每个结果可以有不同的解释:( a )高暴露水平的温暖走廊( b )中等暴露水平的凉爽走廊( c )和( d )相同低暴露水平的黑暗走廊。在( d )中,前景表和陶瓷被高亮显示,具有局部亮化。
🌸🌸对于交互式CE,我们提出了IceNet,它可以在接受用户的注释后增强图像的欠曝光区域和过曝光区域的对比度。具体来说,用户提供一个参数来控制输入图像中的全局亮度和两种类型的涂鸦,以使输入图像中的局部区域变暗或变亮。然后,我们将输入图像和标注输入到IceNet中,IceNet生成伽马图,用于逐像素的伽马校正。更具体地说,我们将涂鸦和输入图像一起送入特征提取器,产生特征图。同时,我们从全局亮度参数中产生一个驱动向量。然后,利用特征图和驱动向量,我们得到根据用户标注自适应生成伽马图。最后,我们通过颜色恢复恢复一幅增强图像,其中我们只调整输入图像的亮度分量,同时保留色度分量。此外,为了用户的方便,我们提供了一个初步增强的图像,并允许用户以交互式的方式进一步增强它。此外,为了有效且可靠地训练IceNet,我们提出了三个可微的损失函数。实验结果表明,IceNet不仅为用户提供了满意的图像,而且在定性和定量上都优于当前最先进的算法。强烈建议观看IceNet实时演示的补充视频。
💕💕💕总的来说,这项工作有以下主要贡献:
①提出了第一个基于CNN的交互式CE算法,称为IceNet,它能够根据用户偏好自适应地产生增强图像或自动地不进行交互。
②使用提出的三个可微的损失函数来训练IceNet,从而实现与用户的交互,并产生令人满意的增强图像。
③通过各种实验结果,我们证明了IceNet可以为用户提供令人满意的结果,优于传统的算法。
2 相关工作
🦋🦋🦋CE,颜色增强,去雾和细节增强之间的增强目标是密切相关但又不同的。本部分简要回顾了CE技术。
A 传统方法
传统的CE技术可以分为三类:直方图方法、参数曲线方法和retinex方法。首先,直方图均衡化试图使输出直方图尽可能均匀。它以较低的计算复杂度有效地增加了对比度,但它可能会过度增强图像,导致对比度超张拉、噪声放大和轮廓伪影。为了克服这些问题,各种直方图方法被开发出来。其次,参数曲线方法,如伽马校正和对数映射,使用参数曲线作为输入和输出像素值之间的转换函数。其中,伽马校正不仅被广泛用于CE,而且还被用于匹配成像设备之间的不同动态范围。第三,假设一幅图像可以分解为反射和照明,一些基于Retinex理论的CE算法已经被提出。这些传统方法在某些情况下产生了很有前途的结果。然而,它们的性能通常依赖于仔细的参数调整;对于不同的输入图像,很难找到可靠有效的参数。
B 基于CNN的方法
最近,许多CNN被设计用于CE。大多数基于CNN的方法都是在成对的数据集上训练的,由成对的低对比度和高对比度图像组成。每对图像从同一场景中采集,或者从一幅高对比度图像合成一幅低对比度图像。然而,由于运动物体的存在,很难对同一场景进行两次拍摄。另一方面,合成的低对比度图像可能不具有真实感。由于这些困难,一些方法采用生成对抗网络和使用未配对的数据集训练他们的网络,这些数据集由从不同场景捕获的低对比度和高对比度图像组成。然而,他们应该谨慎地选择未配对的图像。为了避免这个繁琐的过程,Guo等人提出了一种自监督学习方案,只需要低对比度图像进行训练。然而,所有这些基于CNN的方法都不具有自适应性,无法满足多样化的用户偏好。
C 交互方式
对于交互式CE,专业软件提供了工具,但是使用这些工具需要花费大量的精力和训练。为了减少这种花费,提出了简单的交互方式。Stoel等人提出了一种交互式直方图均衡化方案来增强医学图像的细节。他们的方法允许用户指定一个感兴趣区域( RoI ),并将均衡应用于该区域。格伦德兰和道奇森提出了一种交互式的音调调整方法。当用户在图像上选择关键色调时,它保留这些色调但调整其他色调,同时保持整体色调平衡。Lischinski等人和道奇森等人也提出了交互式方法,用户指定本地CE的RoI。这些交互方法都是基于传统的图像处理。相比之下,据我们所知,提出的IceNet是第一个基于CNN的交互式CE算法。
3 算法
🦋🦋🦋为了使用户能够方便地调整图像对比度,我们开发了IceNet,它可以接受简单的注释,并根据用户的喜好生成增强图像。
A 交互对比度增强
图2说明了所提出的算法。
首先,通过检查输入图像I,用户提供一个曝光水平η∈[ 0、1 ],用于控制全局亮度和两种类型的涂鸦。红色和蓝色的涂抹分别意味着用户希望相应的局部区域变暗和变亮。它们在涂抹图S中分别记为- 1和1,而其他像素被赋值为0。
之后,将RGB彩色图像I转换到YCbCr空间,只调整亮度分量Y,同时保留色度分量。
然后,估计了一个伽马映射Γ来对Y进行逐像素的伽马校正。
最后,通过色彩恢复,得到增强后的图像J。
核心代码:
import torch
import torch.nn as nn
import torch.nn.functional as F
import math
import numpy as npclass IceNet(nn.Module):def __init__(self):super(IceNet, self).__init__()self.relu = nn.ReLU(inplace=True)self.e_conv1 = nn.Conv2d(2,32,3,1,1,bias=True) self.e_conv2 = nn.Conv2d(32,32,3,1,1,bias=True) self.e_conv3 = nn.Conv2d(32,32,3,1,1,bias=True) self.e_conv4 = nn.Conv2d(32,32,3,1,1,bias=True) self.e_conv5 = nn.Conv2d(64,32,3,1,1,bias=True) self.e_conv6 = nn.Conv2d(64,32,3,1,1,bias=True) self.e_conv7 = nn.Conv2d(64,32,3,1,1,bias=True)self.fc1 = nn.Linear(1, 32)self.fc2 = nn.Linear(32, 32)def forward(self, y, maps, e, lowlight=None, is_train=False):b, _, h, w = y.shapex_ = torch.cat([y, maps], 1)# generate adaptive vector according to etaW = self.relu(self.fc1(e))W = self.fc2(W)# feature extractorx1 = self.relu(self.e_conv1(x_))x2 = self.relu(self.e_conv2(x1))x3 = self.relu(self.e_conv3(x2))x4 = self.relu(self.e_conv4(x3))x5 = self.relu(self.e_conv5(torch.cat([x3,x4],1)))x6 = self.relu(self.e_conv6(torch.cat([x2,x5],1)))x_r = self.relu(self.e_conv7(torch.cat([x1,x6],1)))# AGEBx_r = F.conv2d(x_r.view(1, b * 32, h, w),W.view(b, 32, 1, 1), groups=b)x_r = torch.sigmoid(x_r).view(b, 1, h, w) * 10# gamma correctionenhanced_Y = torch.pow(y,x_r)if is_train:return enhanced_Y, x_relse:# color restorationenhanced_image = torch.clip(enhanced_Y*(lowlight/y), 0, 1)return enhanced_image
1)Gamma estimation
🐬伽马校正广泛应用于CE [ 10 ]。选择一个合适的伽玛值是很重要的:小于1的小伽玛使曝光不足的区域变亮,而大于1的大伽玛使曝光过度的区域变暗。伽马值也应考虑个人偏好进行选择。
🐬我们根据用户偏好,通过特征提取器和图2中的自适应伽马估计块( AGEB )为图像中的每个像素确定一个伽马值。特征提取器由7个卷积层组成,层与层之间采用级联的跳跃连接,提高了层与层之间的信息流动性。我们将Y和S串联起来构成特征提取器的输入,从而得到特征图F。然后,给定曝光水平η和特征图F,AGEB生成伽马图Γ。更具体地说,从η出发,AGEB通过两个全连接层产生驱动向量w。然后,对每个像素x,预测像素级伽马值Γ ( x )如公式(1)。
其中,〈·,·〉是内积,φ ( · )是sigmoid函数.因此,我们有0 < Γ ( X ) < 10 .这对于所有像素都是重复的。
2)颜色恢复
对于颜色恢复,我们首先使用其伽马值对亮度图像Y中的每个像素进行伽马校正,得到亮度图像Z。如下述公式(2)。
其中Ymax为最大亮度值(通常为255 )。然后,为了生成增强的RGB彩色图像J,我们采用简单的颜色恢复方法。它保留了颜色比率。如下述公式(3)。
3)个性化初始η
为了方便用户使用,我们提供了一个初步增强的图像,并允许用户通过交互来进一步增强它。为此,我们使用一个二次多项式来估计初始曝光水平η 。如下述公式(4)。
其中,y = 1/N∑x Y ( x )为输入图像的平均亮度,N为像素个数。系数a,b和c由观测值利用最小二乘法得到,其中ηi是用户选择的以平均亮度yi对第i幅输入图像进行增强的曝光水平。当M > 3时,我们进行这种个性化。
B 损失函数
为了训练IceNet,我们使用了三个可微的损失:交互式亮度控制损失Libc、熵损失Lent和平滑度损失Lsmo。下面我们来描述这些损失。
1)交互式亮度控制损失
给定曝光水平η和涂鸦图S,构造目标亮度图T,定义交互式亮度控制损失Libc如公式(5)所示。
因此,式中的增强亮度图像Z 在公式( 2 )符合用户偏好。
为了得到目标亮度T,我们首先在输入亮度Y的基础上加入涂色S。如公式(6)所示。
其中,λ是控制涂抹影响的参数,固定为5。通过添加S,我们控制了局部的亮度水平。接下来,我们将Y '归一化到[ 0、1 ]的范围内,得到Y ~。然后,我们使用双边伽马调整方案来提高黑暗和明亮区域细节的可见性。
其中γ = 5 .值得注意的是,暗区和亮区主要通过Eq( 7 )和( 8 )得到增强。为了保留暗区和亮区的细节,Eq . ( 9 )综合了两者的结果。用户可以通过曝光等级η来控制G的整体亮度。图3说明了η的影响。
图3 ( a )给出了α = 0 . 2、0 . 4、0 . 6和0 . 8时,Y ̄( x )到G ( x )的变换函数。所提出的变换函数在最小值和最大值附近具有陡峭的斜率,因此它们使IceNet能够有效地增强欠曝光和过曝光区域。图3 ( b )—( e )是增强图像的例子。我们发现,随着η的增大,增强后的图像J变得更加明亮。
接下来,对于每个像素x,我们计算一个局部最大值,并按比例缩放,如公式(10)所示。
其中Ω ( x )是关于x的15 × 15窗口.在公式( 5 )中,我们用T代替Ymax × G来抑制相邻像素之间过于不同的目标值,实现更可靠的增强。
2)熵损失
当图像的像素值分布越广泛时,图像的熵越大,传递的信息越多。特别地,最大熵是通过均匀分布来实现的。因此,我们采用熵损失,通过均衡输出图像的直方图来增加全局对比度。然而,直方图不能直接使用,因为其不可区分性。为了克服这个问题,我们设计了一个软直方图。虽然一个像素只对普通直方图的单个bin有贡献,但它以可微的方式对软直方图中的多个bin有贡献。
对于软直方图,我们使用映射函数来表示像素x对第i个bin的贡献,如公式(11)所示。
图4 ( a )给出了σ = 5,10,20时的软映射函数。值得注意的是,σ控制着映射函数的宽度和高度之间的权衡。随着σ的增大,映射函数越来越窄,但越来越高。
在这项工作中,我们设定σ = 10。接下来,我们通过总结所有像素的贡献来制作软直方图h。如公式(12)所示。
然后,我们定义Lent为熵的逆,如公式(13)所示。
3)平滑损失
为了鼓励方程中伽马映射Γ的相邻值之间的平滑变化。我们引入了光滑性损失,如公式(14)所示。
式中,‖·‖F为Frobenius范数。
4)总损失
总体损失定义为三个损失的加权和,如公式(15)所示。
式中,Went和Wsmo为权重。因此,对提出的IceNet进行训练,使3个损失函数最小。首先,Libc使IceNet能够控制全局和局部亮度。其次,Lent鼓励一个平坦的直方图,这样可以增加全局对比度。第三,Lsmo平滑伽马图。
图4 ( b ) ~ ( e )分别给出了各损失的功效。
核心代码:
import torch
import torch.nn as nn
import torch.nn.functional as F
import math
from torchvision.models.vgg import vgg16
import numpy as np
from numpy.testing import assert_almost_equalclass L_ent(nn.Module):def __init__(self, bins, min, max, sigma):super(L_ent, self).__init__()self.bins = binsself.min = minself.max = maxself.sigma = sigmaself.delta = float(max - min) / float(bins)self.centers = float(min) + self.delta * (torch.arange(bins).float().cuda() + 0.5)def forward(self, y):b, _, h, w = y.shapey = y.reshape(b, 1, -1)c = self.centers.reshape(1, -1, 1).repeat(b, 1, 1)x = y - cx = torch.sigmoid(self.sigma * (x + self.delta/2)) - torch.sigmoid(self.sigma * (x - self.delta/2))hist = torch.sum(x, 2)p = hist / (h * w) + 1e-6d = torch.sum((-p * torch.log(p)))return 1/dclass L_int(nn.Module):def __init__(self):super(L_int, self).__init__()def forward(self, x, mean_val, labels):b,c,h,w = x.shapex = torch.mean(x,1,keepdim=True)d = torch.mean(torch.pow(x- labels,2))return dclass L_smo(nn.Module):def __init__(self):super(L_smo,self).__init__()def forward(self,x):batch_size = x.size()[0]h_x = x.size()[2]w_x = x.size()[3]count_h = (x.size()[2]-1) * x.size()[3]count_w = x.size()[2] * (x.size()[3] - 1)h_tv = torch.pow((x[:,:,1:,:]-x[:,:,:h_x-1,:]),2).sum()w_tv = torch.pow((x[:,:,:,1:]-x[:,:,:,:w_x-1]),2).sum()return 2*(h_tv/count_h+w_tv/count_w)/batch_size
C 实现细节
🐬🐬🐬每个卷积层或全连接层的输出通道数为32。在每个卷积层中,执行零填充和ReLU激活。由于采用了8的小批量,因此不采用批归一化处理。我们用高斯随机数初始化IceNet中的所有参数。然后,我们通过Adam优化器以初始学习率0.001更新参数。采用与文献[ 40 ]相同的2002张训练图像。训练图像在SICE [ 49 ]的Part1子集中随机选取,包括欠曝光、正常曝光和过曝光图像。训练在RTX 2080Ti GPU上迭代50次,仅耗时约30分钟。所有训练图像大小调整为512 × 512。为了模拟用户标注,从[ 0.2、0.8]中随机选择一个曝光水平η,分别在随机位置生成0 ~ 5次的红色和蓝色涂鸦。对于这个仿真,每一个划线都是一个半径为10个像素的圆。式( 15 )中,Went = 10,Wsmo = 20。
4 实验
图6 . IceNet与传统算法的定性比较。传统的增强方法在奇数行,而基于CNN的方法在偶数行。
5 IceNet环境配置和运行
1 下载代码
git clone https://github.com/keunsoo-ko/IceNet.git
2 运行
原版demo_interactive.py代码如下:
import model
import os
from PIL import Image
from skimage.color import rgb2ycbcr
import numpy as np
import torch
import matplotlib.pyplot as plt
import cv2#scribble size
points = 10# initialize
l_drawing, r_drawing = False, Falsedef onChange(pos):passdef draw_circle(event,x,y,flags,param):global l_drawing, r_drawingif event == cv2.EVENT_RBUTTONDOWN:r_drawing = Truel_drawing = Falseelif event == cv2.EVENT_LBUTTONDOWN:l_drawing = Truer_drawing = Falseelif event == cv2.EVENT_MOUSEMOVE:if l_drawing == True:cv2.circle(inputs, (x,y), 5, (0,0,255), -1)cv2.circle(scribble, (x,y), points, 1, -1)elif r_drawing == True:cv2.circle(inputs, (x,y), 5, (255,0,0), -1)cv2.circle(scribble, (x,y), points, -1, -1)elif event == cv2.EVENT_LBUTTONUP:l_drawing = Falsecv2.circle(inputs, (x,y), 5, (0,0,255), -1)cv2.circle(scribble, (x,y), points, 1, -1)elif event == cv2.EVENT_RBUTTONUP:r_drawing = Falsecv2.circle(inputs, (x,y), 5, (255,0,0), -1)cv2.circle(scribble, (x,y), points, -1, -1)os.environ['CUDA_VISIBLE_DEVICES']="2"# load image
img = Image.open('/home/ksko/Desktop/Low-light/CVPR2022/BMVC_code/data/test_data/NPE/night (50).jpg')
img = np.asarray(img)# rgb2y -> Tensor
ycbcr = rgb2ycbcr(img)
y = ycbcr[..., 0] / 255.
y = torch.from_numpy(y).float()
y = y[None, None].cuda()# rgb -> Tensor
lowlight = torch.from_numpy(img).float()
lowlight = lowlight.permute(2,0,1)
lowlight = lowlight.cuda().unsqueeze(0) / 255.IceNet = model.IceNet().cuda()
IceNet.load_state_dict(torch.load('model/icenet.pth'))resume = Truewhile(resume):inputs = img.copy() / 255.scribble = np.zeros(inputs.shape[:2])drawing = Falsecv2.namedWindow('image', cv2.WINDOW_AUTOSIZE | cv2.WINDOW_GUI_NORMAL)cv2.setMouseCallback('image', draw_circle)cv2.createTrackbar("threshold", "image", 0, 100, onChange)cv2.setTrackbarPos("threshold", "image", 60)while(1):global_e = cv2.getTrackbarPos("threshold", "image") / 100.# annotationss = torch.from_numpy(scribble)[None, None].float().cuda()eta = torch.Tensor([global_e]).float().cuda()# feedforwardenhanced_image = IceNet(y, s, eta, lowlight)output = enhanced_image[0].permute(1, 2, 0).cpu().detach().numpy()cv2.imshow('image', np.concatenate([inputs, output], 1)[..., ::-1])k = cv2.waitKey(1) & 0xFF# To reset , push key "1"if k == 49:resume = Truebreak# To save results, push key "2"if k == 50:cv2.imwrite('results/eta_%02d.png'%(global_e*100), output[..., ::-1]*255.)# To end demo, push key "Esc"if k == 27:resume = Falsebreakcv2.destroyAllWindows()
适配CPU版的demo_interactive.py代码如下:
import model
import os
from PIL import Image
from skimage.color import rgb2ycbcr
import numpy as np
import torch
import matplotlib.pyplot as plt
import cv2#scribble size
points = 10# initialize
l_drawing, r_drawing = False, Falsedef onChange(pos):passdef draw_circle(event,x,y,flags,param):global l_drawing, r_drawingif event == cv2.EVENT_RBUTTONDOWN:r_drawing = Truel_drawing = Falseelif event == cv2.EVENT_LBUTTONDOWN:l_drawing = Truer_drawing = Falseelif event == cv2.EVENT_MOUSEMOVE:if l_drawing == True:cv2.circle(inputs, (x,y), 5, (0,0,255), -1)cv2.circle(scribble, (x,y), points, 1, -1)elif r_drawing == True:cv2.circle(inputs, (x,y), 5, (255,0,0), -1)cv2.circle(scribble, (x,y), points, -1, -1)elif event == cv2.EVENT_LBUTTONUP:l_drawing = Falsecv2.circle(inputs, (x,y), 5, (0,0,255), -1)cv2.circle(scribble, (x,y), points, 1, -1)elif event == cv2.EVENT_RBUTTONUP:r_drawing = Falsecv2.circle(inputs, (x,y), 5, (255,0,0), -1)cv2.circle(scribble, (x,y), points, -1, -1)os.environ['CUDA_VISIBLE_DEVICES']="2"# load image
img = Image.open('img/bus.png')
# 期待输入的图像有3个通道,而不包含透明度信息
# 可以将图像转换为RGB格式,去除Alpha通道
img = img.convert("RGB")
img = np.asarray(img)# rgb2y -> Tensor
ycbcr = rgb2ycbcr(img)
y = ycbcr[..., 0] / 255.
y = torch.from_numpy(y).float()
y = y[None, None].cpu()# rgb -> Tensor
lowlight = torch.from_numpy(img).float()
lowlight = lowlight.permute(2,0,1)
lowlight = lowlight.cpu().unsqueeze(0) / 255.IceNet = model.IceNet().cpu()
IceNet.load_state_dict(torch.load('model/icenet.pth', map_location=torch.device('cpu')))resume = Truewhile(resume):inputs = img.copy() / 255.scribble = np.zeros(inputs.shape[:2])drawing = Falsecv2.namedWindow('image', cv2.WINDOW_AUTOSIZE | cv2.WINDOW_GUI_NORMAL)cv2.setMouseCallback('image', draw_circle)cv2.createTrackbar("threshold", "image", 0, 100, onChange)cv2.setTrackbarPos("threshold", "image", 60)while(1):global_e = cv2.getTrackbarPos("threshold", "image") / 100.# annotationss = torch.from_numpy(scribble)[None, None].float().cpu()eta = torch.Tensor([global_e]).float().cpu()# feedforwardenhanced_image = IceNet(y, s, eta, lowlight)output = enhanced_image[0].permute(1, 2, 0).cpu().detach().numpy()cv2.imshow('image', np.concatenate([inputs, output], 1)[..., ::-1])k = cv2.waitKey(1) & 0xFF# To reset , push key "1"if k == 49:resume = Truebreak# To save results, push key "2"if k == 50:cv2.imwrite('results/eta_%02d.png'%(global_e*100), output[..., ::-1]*255.)# To end demo, push key "Esc"if k == 27:resume = Falsebreakcv2.destroyAllWindows()
运行demo_interactive.py。
在demo中,按“1”键重置涂鸦图,按“2”键保存增强后的图像,按“Esc”键完成演示。
效果图如下:
3 训练
python Train.py
至此,本文的内容就结束啦💕💕💕。
相关文章:
【论文阅读笔记】IceNet算法与代码 | 低照度图像增强 | IEEE | 2021.12.25
目录 1 导言 2 相关工作 A 传统方法 B 基于CNN的方法 C 交互方式 3 算法 A 交互对比度增强 1)Gamma estimation 2)颜色恢复 3)个性化初始η B 损失函数 1)交互式亮度控制损失 2)熵损失 3)平滑损失 4)总损失 C 实现细节 4 实验 5 IceNet环境配置和运行 1 下载…...
查看 GitHub 仓库的创建时间
查看 GitHub 仓库的创建时间 1. https://api.github.com/repos/{owner}/{repository}2. curl -s https://api.github.com/repos/{owner}/{repository} | jq .created_atReferences 1. https://api.github.com/repos/{owner}/{repository} REST API endpoints for repositories…...
五种被低估的非常规统计检验方法:数学原理剖析与多领域应用价值研究
在当前的数据分析实践中,研究人员往往过度依赖t检验和方差分析(ANOVA)等传统统计方法。但是还存在多种具有重要应用价值但未受到足够重视的统计检验方法,这些方法在处理复杂的实际数据时具有独特优势。本文将详细介绍五种具有重要…...
mysql重置root密码(适用于5.7和8.0)
今天出一期重置mysql root密码的教程,适用于5.7和8.0,在网上搜索了很多的教程发现都没有效果,浪费了很多时间,尝试了多次之后发现这种方式是最稳妥的,那么废话不多说,往下看: 目录 第一步&…...
【AIGC-ChatGPT职业提示词指令】职业发展的航海指南:在人生的十字路口做出明智抉择
引言 在职业发展的海洋中,每个人都会遇到需要重要抉择的时刻。这些关键节点就像航海中的分岔路口,选择不同的航线可能驶向截然不同的目的地。如何在这些关键时刻做出明智的选择,需要我们既要着眼当下的风向,也要洞察远方的航程。…...
【从零开始入门unity游戏开发之——C#篇39】C#反射使用——Type 类、Assembly 类、Activator 类操作程序集
文章目录 前言一、前置知识1、编译器2、程序集(Assembly)3、元数据(Metadata) 二、反射1、反射的概念2、反射的作用3、反射的核心Type 类3.1 Type 类介绍3.2 不同方法获取 Type3.3 获取type类型所在的程序集的相关信息 4、反射的常…...
如何启动CentOS6远程服务器和进行ssh远程登录?
如何启动CentOS 6远程服务器? 在CentOS 6中,启动远程服务器通常涉及到配置SSH服务和VNC服务,以下是详细的步骤: 配置SSH服务 确认是否安装SSH 首先需要检查系统中是否已经安装了SSH服务,打开终端并输入以下命令&am…...
面向机器学习的Java库与平台
学习Java语言中与机器学习相关的各种库与平台,了解每个库的功能,以及可以用它 们解决的问题。 实现机器学习应用时需要具备的Java环境 Weka:一个通用的机器学习平台 Java机器学习库:一系列机器学习算法 Apache Mah…...
AI大模型语音识别转文字
提取音频 本项目作用在于将常见的会议录音文件、各种语种音频文件进行转录成相应的文字,也可从特定视频中提取对应音频进行转录成文字保存在本地。最原始的从所给网址下载对应视频和音频进行处理。下载ffmpeg(https://www.gyan.dev/ffmpeg/builds/packages/ffmpeg-…...
GAN对抗生成网络(一)——基本原理及数学推导
1 背景 GAN(Generative Adversarial Networks)对抗生成网络是一个很巧妙的模型,它可以用于文字、图像或视频的生成。 例如,以下就是GAN所生成的人脸图像。 2 算法思想 假如你是《古董局中局》的文物造假者(Generator,生成器)&a…...
LeetCode - 初级算法 数组(旋转数组)
旋转数组 这篇文章讨论如何通过编程实现数组元素的旋转操作。 免责声明:本文来源于个人知识与公开资料,仅用于学术交流。 描述 给定一个整数数组 nums,将数组中的元素向右轮转 k 个位置,其中 k 是非负数。 示例: 输入: nums = [1,2,3,...
目标检测入门指南:从原理到实践
目录 1. 数据准备与预处理 2. 模型架构设计 2.1 特征提取网络原理 2.2 区域提议网络(RPN)原理 2.3 特征金字塔网络(FPN)原理 2.4 边界框回归原理 2.5 非极大值抑制(NMS)原理 2.6 多尺度训练与测试原理 2.7 损失函数设计原理 3. 损失函数设计 4. 训练策略优化 5. 后…...
连接github和ai的桥梁:GitIngest
Git ingest GitIngest - 将任何 Github 仓库转变为适合 LLM 的友好型提示文本 (https://github.com/cyclotruc/gitingest) 输入 Github 地址或者名称,GitIngest 就会提供该仓库的总结、目录结构、仓库内容的文本内容 你可以复制这些文本与 AI 大模型更好地对话...
百度贴吧的ip属地什么意思?怎么看ip属地
在数字化时代,IP地址不仅是网络设备的唯一标识符,更承载着用户的网络身份与位置信息。百度贴吧作为广受欢迎的社交平台,也遵循相关规定,在用户个人主页等位置展示账号IP属地信息。那么,百度贴吧的IP属地究竟意味着什么…...
5.系统学习-PyTorch与多层感知机
PyTorch与多层感知机 前言PyTroch 简介张量(Tensor)张量创建张量的类型数据类型和 dtype 对应表张量的维度变换:张量的常用操作矩阵或张量计算 Dataset and DataLoaderPyTorch下逻辑回归与反向传播数据表格 DNN(全连结网络&#x…...
wpf 基于Behavior库 的行为模块
Microsoft.Xaml.Behaviors 是一个用于WPF(Windows Presentation Foundation)的行为库,它的主要作用是允许开发者在不修改控件源代码的情况下,为控件添加自定义的行为和交互逻辑。行为库的核心思想是通过定义可重用的行为组件&…...
【一文解析】新能源汽车VCU电控开发——能量回收模块
一、概述 VCU(Vehicle Control Unit,整车控制器)能量回收功能是新能源汽车(如纯电动汽车和混合动力汽车)中非常重要的一个环节。它主要是在车辆减速或制动过程中,将车辆的部分动能转化为电能,并…...
鸿蒙TCPSocket通信模拟智能家居模拟案例
效果图 一、智能家居热潮下的鸿蒙契机 在当下科技飞速发展的时代,智能家居已如浪潮般席卷而来,深刻地改变着我们的生活方式。从能依据环境光线自动调节亮度的智能灯具,到可远程操控、精准控温的智能空调,再到实时监测健康数据的智…...
【Spring Boot 实现 PDF 导出】
Spring Boot 实现 PDF 导出 在Spring Boot应用程序中实现PDF导出功能,可以选择多种库和技术栈。每种方法都有其优缺点,适用于不同的场景。以下是四种常见的方式:iText、Apache PDFBox、JasperReports 和 Thymeleaf Flying Saucer。我将详细…...
【Python】selenium结合js模拟鼠标点击、拦截弹窗、鼠标悬停方法汇总(使用 execute_script 执行点击的方法)
我们在写selenium获取网络信息的时候,有时候我们会受到对方浏览器的监控,对方通过分析用户行为模式,如点击、滚动、停留时间等,网站可以识别出异常行为,进而对Selenium爬虫进行限制。 这里我们可以加入JavaScript的使…...
leetcode hot 100 前k个高平元素
347. 前 K 个高频元素 已解答 中等 相关标签 相关企业 给你一个整数数组 nums 和一个整数 k ,请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案。 class Solution(object):def topKFrequent(self, nums, k):""":type nums: Lis…...
数据结构漫游记:静态双向链表
嘿,各位技术潮人!好久不见甚是想念。生活就像一场奇妙冒险,而编程就是那把超酷的万能钥匙。此刻,阳光洒在键盘上,灵感在指尖跳跃,让我们抛开一切束缚,给平淡日子加点料,注入满满的pa…...
Object.defineProperty() 完整指南
Object.defineProperty() 完整指南 1. 基本概念 Object.defineProperty() 方法允许精确地添加或修改对象的属性。默认情况下,使用此方法添加的属性是不可修改的。 1.1 基本语法 Object.defineProperty(obj, prop, descriptor)参数说明: obj: 要定义…...
1Panel自建RustDesk服务器方案实现Windows远程macOS
文章目录 缘起RustDesk 基本信息实现原理中继服务器的配置建议 中继服务器自建指南准备服务器安装1Panel安装和配置 RustDesk 中继服务防火墙配置和安全组配置查看key下载&安装&配置客户端设置永久密码测试连接 macOS安装客户端提示finder写入失败hbbs和hbbr说明**hbbs…...
nginx学习之路-windows系统安装nginx
文章目录 1. 下载2. 启动3. 验证参考文档 1. 下载 官方下载地址:https://nginx.org/en/download.html 可以下载windows版本,如nginx-1.26.2.zip。解压后,加入系统变量。 2. 启动 可以使用命令行启动(windows系统自带的cmd可能…...
Paimon_01_241020
1. 概述 1.1. 核心特点 统一批处理和流处理(流和批同一套代码)数据湖能力多种引擎平权变更日志生成丰富的表类型(主键表、append-only,有序的流式读取来代替消息队列)模式演化(schema变更) 1…...
人工智能:变革时代的核心驱动力
求各位观众老爷看一看 先声明一下,该内容由于篇幅过长,可能会有一些地方存在一些小问题请大家谅解 观众老爷们,点个免费的赞和关注呗,您们的支持就是我最大的动力~ 人工智能:变革时代的核心驱动力 一、引言 在当今…...
【机器学习】工业 4.0 下机器学习如何驱动智能制造升级
我的个人主页 我的领域:人工智能篇,希望能帮助到大家!!!👍点赞 收藏❤ 随着科技的飞速发展,工业 4.0 浪潮正席卷全球制造业,而机器学习作为这一变革中的关键技术,正以前…...
数据分析-Excel
数据类型和函数初步 Excel中有文本类型和数值类型–但是无法用肉眼分辨出来isnumber来区分是否是数值类型text和value函数可以完成数值类型以及文本类型的转换单元格第一位输入’方式明确输入的是文本sum函数必须是数值类型 文本连接-and-or-not-if-mod-max函数 字符串的连接…...
Kubernetes第二天
1.pod运行一个容器 1.创建目录 mkdir -p /manifests/pod 2.编写pod资源清单文件 vim 01-myweb.yaml 说明: apiVersion:指的是Api的版本 metadata:资源的元数据 spec:用户期望的资源的运行状态 status:资源实际的运行状态 由于拉取远…...
【Java 学习】深度剖析Java多态:从向上转型到向下转型,解锁动态绑定的奥秘,让代码更优雅灵活
💬 欢迎讨论:如对文章内容有疑问或见解,欢迎在评论区留言,我需要您的帮助! 👍 点赞、收藏与分享:如果这篇文章对您有所帮助,请不吝点赞、收藏或分享,谢谢您的支持&#x…...
Kerberos用户认证-数据安全-简单了解-230403
hadoop安全模式官方文档:https://hadoop.apache.org/docs/r2.7.2/hadoop-project-dist/hadoop-common/SecureMode.html kerberos是什么 kerberos是计算机网络认证协议,用来在非安全网络中,对个人通信以安全的手段进行身份认证。 概念&#…...
大中厂面试经验分享:如何使用消息队列(MQ)解决系统问题
在大中型互联网公司中,消息队列(MQ)作为一种关键的分布式系统组件,广泛应用于解决系统中的高并发、异步处理、解耦等问题。 在面试中,尤其是针对后端工程师或系统架构师的职位,面试官常常会通过询问消息队列…...
c#String和StringBuilder
目录 一,String 1,string的特点: 2,string常用方法 (1)Length (2)Substring() (3)ToUpper() (4)ToLower() (5&…...
【人工智能机器学习基础篇】——深入详解强化学习之常用算法Q-Learning与策略梯度,掌握智能体与环境的交互机制
深入详解强化学习之常用算法:Q-Learning与策略梯度 强化学习(Reinforcement Learning, RL)作为机器学习的一个重要分支,近年来在多个领域取得了显著成果。从棋类游戏的人机对战到自主驾驶汽车,强化学习技术展示了其强大…...
jQuery学习笔记2
jQuery 属性操作 <body><a href"http://www.itcast.cn" title"都挺好">都挺好</a><input type"checkbox" name"" id"" checked /><div index"1" data-index"2">我是div&…...
发现API安全风险,F5随时随地保障应用和API安全
分析数据显示,目前超过90%的基于Web的网络攻击都以API端点为目标,试图利用更新且较少为人所知的漏洞,而这些漏洞通常是由安全团队未主动监控的API所暴露。现代企业需要一种动态防御策略,在风险升级成代价高昂、令人警惕且往往无法…...
移动端如何实现上拉加载
一、理解上拉加载的原理 上拉加载是一种在移动端很常见的交互方式,其原理是当用户在页面上向上滑动(即滚动条接近底部)时,触发一个加载更多数据的操作。这通常涉及到对滚动事件的监听以及判断滚动位置是否达到了触发加载的阈值。…...
the request was rejected because no multipart boundary was found
文章目录 1. 需求描述2. 报错信息3. 探索过程 1. 使用postman 排除后端错误2. 搜索网上的解决方法3. 解决方法 1. 需求描述 想要在前端上传一个PDF 发票,经过后端解析PDF之后,将想要的值自动回填到对应的输入框中 2. 报错信息 org.apache.tomcat.u…...
Android 自定义shell命令
模拟触摸、按键等操作,直接在命令行输入对应命令即可。命令行如何识别并操作此命令,执行操作的是shell程序,还是java程序?是不是可以添加自定义的命令? 以下在Android13的代码中分析input命令 Android系统中使用了一…...
HTML5滑块(Slider)
HTML5 的滑块(Slider)控件允许用户通过拖动滑块来选择数值。以下是如何实现一个简单的滑块组件的详细说明。 HTML5 滑块组件 1. 基本结构 使用 <input type"range"> 元素可以创建一个滑块。下面是基本实现的代码示例: <…...
《SwiftUI 实现点击按钮播放 MP3 音频》
功能介绍 点击按钮时,应用会播放名为 yinpin.mp3 的音频文件。使用 AVAudioPlayer 来加载和播放音频。 关键点: 按钮触发:点击按钮会调用 playAudio() 播放音频。音频加载:通过 Bundle.main.url(forResource:) 加载音频文件。播…...
表单元素(标签)有哪些?
HTML 中的表单元素(标签)用于收集用户输入的数据,常见的有以下几种: 文本输入框 <input type"text">:用于单行文本输入,如用户名、密码等。可以通过设置maxlength属性限制输入字符数&…...
大型ERP系统GL(总账管理)模块需求分析
主要介绍了GL系统的需求分析,包括系统概述、功能描述、帐薄管理、报表管理、期末处理、财务报表以及凭证的快速输入方式、可用性设计、保存、自动审核和打印等方面的内容。系统概述部分介绍了系统的功能结构和模块流程图。 功能描述部分详细描述了系统的基础资料和业…...
SQL常用语句(基础)大全
SQL语句的类型 1.DDL 1.库2.表 2.DML 1.插入数据 insert inot2.删除数据 delete / truncate3.修改数据 update set 3.DQL 1.无条件查询2.查询 什么开始 到什么结束3.指定条件查询 1.单个条件 ro in2.多个条件 and4.查询不为NULL值 is not null ,为NULL值 is null5.模糊查询 li…...
关于HarmonyOS Next中卡片的使用方法
关于Harmony OS中卡片的使用方法 在Harmony OS中,静态卡片是一种非常有用的组件,用于提供应用内功能组件的交互和信息展示。本文将详细介绍如何在Harmony OS中使用静态卡片以及相关的API接口。 1. 概述 静态卡片是Harmony OS中的一种交互组件…...
Retrofit和rxjava 实现窜行请求,并行请求,循环多次请求,递归请求,错误重试
在使用 Retrofit 和 RxJava 时,可以通过多种方式实现多次请求,比如串行请求、并行请求、依赖请求等。以下是一些常见的实现方式: 1. 串行请求(依赖关系) 一个请求的结果作为另一个请求的输入,可以用 flat…...
C# OpenCV机器视觉:目标跟踪
在一个阳光明媚的下午,阿强正在实验室里忙碌,突然他的同事小杨走了进来,脸上挂着一丝困惑。 “阿强,我的目标跟踪项目出了问题!我想跟踪一个移动的物体,但总是跟丢!”小杨一边说,一…...
LeetCode 191 位1的个数
计算正整数二进制表示中汉明重量的两种实现方式对比 在编程的世界里,我们常常会遇到一些有趣又实用的小问题,今天就来和大家分享一下如何计算一个正整数二进制表示中设置位(也就是 1 的个数,专业术语叫汉明重量)的问题…...
【软件测试面试】银行项目测试面试题+答案(二)
前言 面试题:贷款有哪几种形式? 贷款是指金融机构或其他信贷机构向借款人提供资金,并按照约定的条件和期限收取一定利息的行为。根据贷款的不同形式,贷款可以分为以下几种: 按照还款方式分:分期付款贷款、到期一次…...