IDR: Self-Supervised Image Denoising via Iterative Data Refinement

news2024/11/24 9:21:29

文章目录

  • IDR: Self-Supervised Image Denoising via Iterative Data Refinement
      • 1. noisy-clean pair 比较难获取
      • 2. noiser-noisy pair 比较容易获取,但是训练效果呢?
        • 2.1 noiser-noisy 训练的模型,能够对 noisy 图像一定程度的降噪
        • 2.2 noiser-noisy数据 越接近 noisy-clean 数据,训练的效果越好。
      • 3.通过训练 让noiser-noisy数据 更接近 noisy-clean 数据
      • 4.Fast Iterative Data Refinement
      • 5. sensenoise-500 dataset
        • 5.1 数据集 error
      • 6.训练

IDR: Self-Supervised Image Denoising via Iterative Data Refinement

IDR 是一个无监督降噪模型。

1. noisy-clean pair 比较难获取

noisy-clean pair:
x: noidy image, y: clean image
但是 y比较难获取

noisr-noisy pair
x + n , x

在这里插入图片描述

对噪声图像再添加噪声,得到 噪声更大的图像。

这里的n表示的是sensor的噪声模型(也可以是采样得到的,参考作者另一篇论文rethinking noise).

2. noiser-noisy pair 比较容易获取,但是训练效果呢?

作者的两个发现:

2.1 noiser-noisy 训练的模型,能够对 noisy 图像一定程度的降噪

如下图:

在这里插入图片描述

2.2 noiser-noisy数据 越接近 noisy-clean 数据,训练的效果越好。

在这里插入图片描述

3.通过训练 让noiser-noisy数据 更接近 noisy-clean 数据

1.训练F0,生成新的数据集
在这里插入图片描述

2.利用新的数据集训练F1.
由于 新的数据集 更接近 noisy-clean 数据,因此训练的结果对于noisy的表现会更好。
在这里插入图片描述

3.因此可以迭代训练,不断生成新的less biased数据集, 训练新的model
在这里插入图片描述

4.Fast Iterative Data Refinement

以上迭代训练需要生成多次数据集,训练多次model.

作者提出改进的方案:
a.每个epoch refine一次dataset, 不需要训练到完全收敛
b.利用上个epoch的model初始化下一个epoch的model
*
这样改进下来,和正常训练差别不大了,除了每个epoch要更新一次数据集。

实际的效果如下:
每次迭代,降噪效果都有改善。

请添加图片描述

5. sensenoise-500 dataset

IMX586, 3000x4000 pixels, low light conditions.

64 帧 = 4 帧 正常曝光noisy image + 60 帧 长曝光(1s-2s) use median value ad ground truth

正常曝光和长曝光的图像如何 保持亮度一致呢?需要设置 iso 和曝光时间:
在这里插入图片描述

图像示例:
在这里插入图片描述

最终图像数据是1010张(505pairs):
在这里插入图片描述

dng是噪声图, npy是groundtruth

5.1 数据集 error

部分ground truth 高亮区域偏红色。

6.训练

4种方案训练sensenoise 500

  1. pair
  2. add GP noise
  3. idr(本文)
  4. noise2noise: add gp noise

由于不知道数据集的实际噪声参数。因此add noise都是添加的一定范围

k = np.random.uniform(0.8, 3)
scale = np.random.uniform(1, 30)
# k = torch.FloatTensor(k)
# scale = torch.FloatTensor(scale)
in_img1 = add_noise_torch(gt_img, k, scale).to(device)
in_img2 = add_noise_torch(gt_img, k, scale).to(device) # 是否需要转化为int16类型,因为实际raw图数据都是整数
gt_img = gt_img.to(device)
# print(in_img.min(), in_img.max(), in_img.mean(), in_img.var())
# print(gt_img.min(), gt_img.max(), gt_img.mean(), gt_img.var()) # more and more little
gt_img = gt_img / 1023
in_img = in_img1 / 1023
in_img = torch.clamp(in_img, 0, 1)
in_img2 = in_img2 / 1023
in_img2 = torch.clamp(in_img2, 0, 1)

idr训练:

import glob
import os.path

import cv2
import numpy as np
import rawpy
import torch
import torch.optim as optim
from torch import nn
from torch.utils.data import DataLoader
from tqdm import tqdm

from skimage.metrics import peak_signal_noise_ratio as compare_psnr
from skimage.metrics import structural_similarity as compare_ssim
from model import UNetSeeInDark
from sensenoise500 import add_noise_torch
from sid_dataset_sensenoise500 import sensenoise_dataset, apply_wb_ccm, sensenoise_dataset_2, \
    sensenoise_dataset_addnoise, sensenoise_dataset_addnoise_2, choose_k_sigma
import torchvision


if __name__ == "__main__":
    # 1.当前版本信息
    print(torch.__version__)
    print(torch.version.cuda)
    print(torch.backends.cudnn.version())
    print(torch.cuda.get_device_name(0))

    np.random.seed(0)
    torch.manual_seed(0)
    torch.cuda.manual_seed_all(0)
    torch.backends.cudnn.deterministic = True
    torch.backends.cudnn.benchmark = False

    # 2. 设置device信息 和 创建model
    model = UNetSeeInDark()
    model._initialize_weights()

    gpus = [1]
    #model = nn.DataParallel(model, device_ids=gpus)
    device = torch.device('cuda:1')
    model = model.cuda(device=gpus[0])
    
    # 6. 是否恢复模型
    resume = 0
    last_epoch = 0
    lr_epoch = 1
    if resume and last_epoch > 1:
        model.load_state_dict(torch.load(os.path.join(save_model_dir, f'checkpoint_{last_epoch:04d}.pth'), map_location=device))
        lr_epoch = 0.5**(last_epoch // 500)
    
    # 3. dataset 和 data loader, num_workers设置线程数目,pin_memory设置固定内存
    # train_dataset = sensenoise_dataset_addnoise_2(mode='train')
    # train_dataset_loader = DataLoader(train_dataset, batch_size=4*len(gpus), shuffle=True, num_workers=8, pin_memory=True)

    eval_dataset = sensenoise_dataset_2(mode='eval')
    eval_dataset_loader = DataLoader(eval_dataset, batch_size=1, num_workers=8, pin_memory=True)
    print('load dataset !')
	files = glob.glob(os.path.join('/home/wangzhansheng/dataset/sidd/SenseNoise500/final_datasetv3/', '*.dng'))
    files = sorted(files)[:400]
    datas = []
    for file in files:
        input_path = file

        txt_path = input_path[:-4] + '.txt'
        para = np.loadtxt(txt_path)
        wb_gain = np.array(para[:3]).astype(np.float32)
        ccm = np.array(para[3:12]).astype(np.float32).reshape(3, 3)
        iso = para[-1]
        # gt_raw = np.load(gt_path).astype(np.int32)
        # gt_raw = np.dstack((gt_raw[0::2, 0::2], gt_raw[0::2, 1::2], gt_raw[1::2, 0::2], gt_raw[1::2, 1::2]))

        input_raw = rawpy.imread(input_path).raw_image_visible.astype(np.float32)
        input_raw = np.dstack((input_raw[0::2, 0::2], input_raw[0::2, 1::2], input_raw[1::2, 0::2], input_raw[1::2, 1::2]))

        datas.append([input_raw, wb_gain, ccm, input_path, iso])
        print(file, len(datas))

    # 4. 损失函数 和  优化器
    loss_fn = nn.L1Loss()
    learning_rate = 3*1e-4
    optimizer = optim.Adam(model.parameters(), lr=learning_rate)
    lr_step = 500
    scheduler = torch.optim.lr_scheduler.StepLR(optimizer, lr_step, gamma=0.5)

    # 5. hyper para 设置
    epochs = 5000
    save_epoch = 100
    save_model_dir = 'saved_model_sensenoise500_addnoise_single_idr'

    eval_epoch = 100
    save_sample_dir = 'saved_sample_sensenoise500_addnoise_single_idr'
    if not os.path.exists(save_model_dir):
        os.makedirs(save_model_dir)


    # 7. 训练epoch
    epoch_infos = []
    eval_infos = []
    
    
    patch_size = 512
    for epoch in range(last_epoch+1, epochs + 1):
        print('current epoch:', epoch, 'current lr:', optimizer.state_dict()['param_groups'][0]['lr'])
        if epoch < 101:
            save_epoch = 10
            eval_epoch = 10
        else:
            save_epoch = 100
            eval_epoch = 100
        # 8. train loop
        model_copy = UNetSeeInDark().to(device)
        model_copy.load_state_dict(model.state_dict())
        model_copy.eval()


        model.train()
        g_loss = []
        g_psnr = []

        kk = 0
        for idx in tqdm(np.random.permutation(len(datas))):
            data = datas[idx]
        #for data in np.random.shuffle(datas):
            # gt_path = file
            # txt_path = gt_path[:-4] + '.txt'
            # para = np.loadtxt(txt_path)
            # wb_gain = np.array(para[:3]).astype(np.float32)
            # ccm = np.array(para[3:12]).astype(np.float32).reshape(3, 3)
            # iso = para[-1]
            #
            # gt_raw = np.load(gt_path).astype(np.int32)
            # iso, k, sigma = choose_k_sigma(iso/2)
            # k = k * np.random.uniform(0.8, 1.2)
            # sigma2 = np.sqrt(sigma) * np.random.uniform(0.8, 1.1)
            # short_raw = k * np.random.poisson(gt_raw / k) + np.random.normal(0., sigma2, gt_raw.shape)
            # gt_raw = gt_raw / 1023
            # short_raw = short_raw / 1023

            input_raw, wb_gain, ccm, gt_path, iso = data
            # crop
            h, w, c = input_raw.shape
            h1 = np.random.randint(0, h - patch_size)
            w1 = np.random.randint(0, w - patch_size)
            # short_raw = short_raw[h1:h1 + patch_size, w1:w1 + patch_size, :]
            short_raw = input_raw[h1:h1 + patch_size, w1:w1 + patch_size, :]

            # augment
            if np.random.randint(2, size=1)[0] == 1:  # random flip
                short_raw = np.flip(short_raw, axis=0)
                #gt_raw = np.flip(gt_raw, axis=0)
            if np.random.randint(2, size=1)[0] == 1:
                short_raw = np.flip(short_raw, axis=1)
                #gt_raw = np.flip(gt_raw, axis=1)
            if np.random.randint(2, size=1)[0] == 1:  # random transpose
                short_raw = np.transpose(short_raw, (1, 0, 2))
                #gt_raw = np.transpose(gt_raw, (1, 0, 2))
            #in_img = torch.permute(input_patch, (0,3,1,2)).cuda(device=gpus[0])

            short_raw = np.ascontiguousarray(short_raw[np.newaxis, ...])
            gt_img = torch.from_numpy(short_raw).permute(0, 3, 1, 2)


            if epoch > last_epoch + 1:
                model_copy.eval()
                with torch.no_grad():

                    gt_img_last = gt_img.to(device) / 1023
                    gt_img = model_copy(gt_img_last).cpu()
                    gt_img = torch.clamp(gt_img* 1023, 0, 1023)
                    # print(gt_img_last.min(), gt_img_last.max(), gt_img_last.mean(), gt_img_last.var())
                    # print(gt_img.min(), gt_img.max(), gt_img.mean(), gt_img.var()) # more and more little
                    if kk  > 50000:
                        im1 = gt_img_last.cpu().float().numpy().squeeze().transpose(1, 2, 0)
                        im2 = gt_img.float().numpy().squeeze().transpose(1, 2, 0) / 1023
                        im1 = im1[..., [0, 1, 3]] ** (1 / 2.2)
                        im2 = im2[..., [0, 1, 3]] ** (1 / 2.2)
                        im1 = np.clip(im1 * 255 + 0.5, 0, 255).astype(np.uint8)
                        im2 = np.clip(im2 * 255 + 0.5, 0, 255).astype(np.uint8)
                        save_sample_dir3 = save_sample_dir + f'/{epoch:04}dd/'
                        if not os.path.isdir(save_sample_dir3):
                            os.makedirs(save_sample_dir3)

                        filename_save = os.path.basename(gt_path)[:-4]
                        cv2.imwrite(os.path.join(save_sample_dir3, '%s_dddd1.png' % (filename_save)), im1[..., ::-1])
                        cv2.imwrite(os.path.join(save_sample_dir3, '%s_dddd2.png' % (filename_save)),
                                    im2[..., ::-1])
            iso, k, sigma = choose_k_sigma(iso/2)

            # k = np.random.uniform(0.8, 3)
            # scale = np.random.uniform(1, 30)
            # k = torch.FloatTensor(k)
            # scale = torch.FloatTensor(scale)
            scale = np.sqrt(sigma)
            in_img = add_noise_torch(gt_img, k, scale).to(device)
            gt_img = gt_img.to(device)
            # print(in_img.min(), in_img.max(), in_img.mean(), in_img.var())
            # print(gt_img.min(), gt_img.max(), gt_img.mean(), gt_img.var()) # more and more little
            gt_img = gt_img / 1023
            in_img = in_img / 1023
            in_img = torch.clamp(in_img, 0, 1)

            # print(gt_img.shape, gt_img.min(), gt_img.max())
            # print(in_img.shape, in_img.min(), in_img.max())
            # print(wb_gain, ccm, iso, gt_path)

            out = model(in_img)
            loss = loss_fn(out, gt_img)

            optimizer.zero_grad()
            loss.backward()
            optimizer.step()

            # training result
            g_loss.append(loss.data.detach().cpu())
            mse_value = np.mean((out.cpu().data.numpy() - gt_img.cpu().data.numpy()) ** 2)
            psnr = 10. * np.log10(1. / mse_value)
            g_psnr.append(psnr)

        mean_loss = np.mean(np.array(g_loss))
        mean_psnr = np.mean(np.array(g_psnr))
        print(f'epoch{epoch:04d} ,train loss: {mean_loss},train psnr: {mean_psnr}')
        epoch_infos.append([epoch, mean_loss, mean_psnr])

        # 9. save model
        if epoch % save_epoch == 0:
            save_model_path = os.path.join(save_model_dir, f'checkpoint_{epoch:04d}.pth')
            torch.save(model.state_dict(), save_model_path)
        # 10. eval test and save some samples if needed
        if epoch % eval_epoch == 0:
            model.eval()
            k = 0

            with torch.no_grad():
                psnr_12800_0 = []
                psnr_12800_1 = []

                ssim_12800_0 = []
                ssim_12800_1 = []

                for data in tqdm(eval_dataset_loader):
                    input_patch, gt_patch, wb_gain, ccm, gt_path, iso = data

                    in_img = input_patch.permute(0, 3, 1, 2).cuda(device=gpus[0])
                    gt_img = gt_patch.permute(0, 3, 1, 2).cuda(device=gpus[0])

                    out = model(in_img)

                    im1 = gt_img.detach().cpu().float().numpy().squeeze().transpose(1,2,0)
                    im2 = out.detach().cpu().float().numpy().squeeze().transpose(1,2,0)
                    im1 = np.clip(im1 * 255 + 0.5, 0, 255).astype(np.uint8)
                    im2 = np.clip(im2 * 255 + 0.5, 0, 255).astype(np.uint8)

                    temp_psnr = compare_psnr(im1, im2, data_range=255)
                    temp_ssim = compare_ssim(im1, im2, data_range=255, channel_axis=-1)
                    if iso <= 12800:
                        psnr_12800_0.append(temp_psnr)
                        ssim_12800_0.append(temp_ssim)
                    else:
                        psnr_12800_1.append(temp_psnr)
                        ssim_12800_1.append(temp_ssim)

                    # show training out
                    save_img = 1
                    if save_img and k<10:
                        k += 1
                        im_input = in_img.detach().permute(0, 2, 3, 1).cpu().float().numpy()[0]
                        im_gt = gt_img.detach().permute(0, 2, 3, 1).cpu().float().numpy()[0]
                        im_out = out.detach().permute(0, 2, 3, 1).cpu().float().numpy()[0]
                        wb_gain = wb_gain.data.cpu().numpy()[0]
                        ccm = ccm.data.cpu().numpy()[0]
                        gt_path = gt_path[0]

                        pattern_sensenoise500 = 'RGGB'
                        im_input_srgb = apply_wb_ccm(im_input[..., [0, 1, 3]], wb_gain, ccm, pattern_sensenoise500)
                        im_gt_srgb = apply_wb_ccm(im_gt[..., [0, 1, 3]],  wb_gain, ccm, pattern_sensenoise500)
                        im_out_srgb = apply_wb_ccm(im_out[..., [0, 1, 3]],  wb_gain, ccm, pattern_sensenoise500)

                        im_input_srgb = np.clip(im_input_srgb * 255 + 0.5, 0, 255).astype(np.uint8)
                        im_gt_srgb = np.clip(im_gt_srgb * 255 + 0.5, 0, 255).astype(np.uint8)
                        im_out_srgb = np.clip(im_out_srgb * 255 + 0.5, 0, 255).astype(np.uint8)

                        save_sample_dir2 = save_sample_dir + f'/{epoch:04}/'
                        if not os.path.isdir(save_sample_dir2):
                            os.makedirs(save_sample_dir2)

                        # save_sample_path = os.path.join(save_sample_dir2, os.path.basename(gt_path)[:-4]+'.png')
                        # cv2.imwrite(save_sample_path, np.hstack((im_gt_srgb,im_input_srgb, im_out_srgb))[..., ::-1])

                        filename_save = os.path.basename(gt_path)[:-4]
                        cv2.imwrite(os.path.join(save_sample_dir2, '%s_psnr_%.2f_out.png' % (filename_save, temp_psnr)), im_out_srgb[...,::-1])
                        cv2.imwrite(os.path.join(save_sample_dir2, '%s_NOISY.png' % (filename_save)), im_input_srgb[...,::-1])
                        cv2.imwrite(os.path.join(save_sample_dir2, '%s_GT.png' % (filename_save)), im_gt_srgb[...,::-1])

                print('eval dataset  psnr: ', np.array(psnr_12800_0).mean(), np.array(psnr_12800_1).mean())
                print('eval dataset  ssim: ', np.array(ssim_12800_0).mean(), np.array(ssim_12800_1).mean())
                eval_infos.append([epoch, np.array(psnr_12800_0).mean(), np.array(psnr_12800_1).mean(), np.array(ssim_12800_0).mean(), np.array(ssim_12800_1).mean()])
        scheduler.step() # 更新学习率

    np.savetxt('train_infos.txt',  epoch_infos, fmt='%.4f') # epoch loss psnr
    np.savetxt('eval_infos.txt', eval_infos, fmt='%.4f')    # epoch psnr, ssim

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

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

相关文章

基于Nginx深入浅出亿级流量架构设计(持续更新2023.7.18)

基于Nginx深入浅出亿级流量架构设计 环境准备/安装部署Nginx四个发行版本简单介绍Nginx的安装 Nginx的目录结构与基本运行原理及其最小配置解析Nginx虚拟主机与域名配置ServerName匹配规则反向代理在系统结构中的应用场景Nginx的反向代理配置 环境准备/安装部署 虚拟机使用VMw…

STM32F4_FLASH模拟EEPROM

目录 前言 1. 内部FLASH简介 2. 内部FLASH写入过程 3. 内部FLASH库函数 4. FLASH的读写保护及解除 5. FLASH相关寄存器 6. 实验程序 6.1 main.c 6.2 STMFlash.c 6.3 STMFlash.h 前言 STM32F4本身并没有自带EEPROM&#xff0c;但是STM32F4具有IAP功能&#xff0c;也就…

初阶数据结构——排序

目录 排序的概念常见排序算法插入排序希尔排序选择排序堆排序冒泡排序快速排序hoare挖坑法前后指针法快排的时间复杂度三路划分三数取中和随机数选中快排的非递归版本快速排序的总结 归并排序归并的递归版本归并的非递归版本 内排序和外排序非比较排序稳定性排序算法复杂度和稳…

测试基础 Android 应用测试总结

目录 启动&#xff1a; 功能介绍&#xff0c;引导图&#xff0c;流量提示等&#xff1a; 权限&#xff1a; 文件错误 屏幕旋转&#xff1a; 流量&#xff1a; 缓存&#xff08;/sdcard/data/com.your.package/cache/&#xff09;&#xff1a; 正常中断&#xff1a; 异…

Android 自定义CheckBox样式,设置切换背景图,类似于RadioButton

文章目录 概要自定义CheckBok资源文件如下使用方法实现效果 概要 目前要实现类似于Radiobutton选择按钮&#xff0c;如果只有一个RadioButton&#xff0c;就不能和radio Group连用&#xff0c;导致选择没办法取消&#xff0c;如果要实现只能代码中进行操作&#xff0c;过于繁琐…

项目管理软件选择指南:最佳实践与避坑指南

当今企业中&#xff0c;协作工具是必不可少的&#xff0c;每个企业都会寻找最适合自己的协作工具来提高工作效率。在这些协作工具中&#xff0c;Zoho Projects项目协作工具是最常用的一种&#xff0c;因为它能够为团队提供一个集任务、项目、文档、IM、目标、日历、甘特图、工时…

MIT 6.829 -- L2 The Internetworking Problem

MIT 6.829 -- L2 The Internetworking Problem 前言The Internetworking Problem: Many Different NetworksGateWays互联网设计原则通用性原则健壮性原则互联网缺点互联网协议标准流程 最早的TCP/IP今天的TCP/IP: IPv4地址分片和重组Time-to-live&#xff08;TTL&#xff09;Ty…

2023 7.17~7.23 周报 (最近读的论文方法论分析)

0 上周回顾 上周完成了RTM的研究学习, 完成了进一步阅读论文所需的知识储备. 同时从代码层面深度解析了正演和RTM存在的关系, 发掘了很多富有参考意义的信息. 1 本周计划 深度剖析论文《Deep-Learning Full-Waveform Inversion Using Seismic Migration Images》的方法体系,…

计算机网络——VLan介绍

学习视频&#xff1a; 网工必会&#xff0c;十分钟搞明白&#xff0c;最常用的VLAN技术_哔哩哔哩_bilibili 技术总结&#xff1a;VLAN&#xff0c;网络中最常用的技术&#xff0c;没有之一_哔哩哔哩_bilibili 全国也没几个比我讲得好的&#xff1a;VLAN虚拟局域网 本来补充了…

微服务day1——微服务入门

一、认识微服务 1、单体架构 将业务的所有功能集中在一个项目中开发&#xff0c;打成一个包部署。 优点 架构简单部署成本低 缺点 耦合度高 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fPfsQXAn-1689593800699)(https://picture.wangkay.tec…

探索OLED拼接屏的特点及在莱山的场景化应用

涞山oled拼接屏是一种高清晰度的显示屏&#xff0c;由多个oled屏幕拼接而成。它可以用于各种场合&#xff0c;如商业展示、广告宣传、会议演示等。涞山oled拼接屏具有以下特点&#xff1a; 1. 高清晰度&#xff1a;oled屏幕具有高对比度、高亮度、高色彩饱和度等特点&#xff0…

jeecg-boot sql注入漏洞解决

输入下面的链接地址&#xff0c;就会出现下面的获取数据&#xff0c;这个漏洞还是比较严重的啊 http://localhost:8080/nbcio-boot/sys/ng-alain/getDictItemsByTable/%20from%20sys_user/*,%20/x.js 通过上面方式可以获取用户信息了 如下&#xff1a; RequestMapping(valu…

层次分析模型

层次分析法是对一些较为复杂、模糊的问题做出决策的简易方法 这里涉及一个决策概念的理解 初步理解应该是一种评价类的模型 层次分析法的典型应用&#xff1a; 1、用于最佳方案的选取 2、用于评价类分析 3、用于指标体系的优选 层次分析法的名字中层次的原因 层次分析法的步骤…

Skywalking使用说明

需求背景 随着分布式的盛行&#xff0c;系统的复杂度也逐步增加&#xff0c;不同服务间的交互对性能的定位提出了更高的要求。任意一个节点的异常&#xff0c;都可能对业务系统造成损失。对于链路追踪&#xff0c;迫切需要一个优秀的监测工具。 需求如下 功能性需求 请求链…

怎么把word文档转换成pdf文件?这三个方法超级实用!

word文档编辑完成后&#xff0c;通常会将其转换为PDF格式&#xff0c;以使文档内容更加简洁。那么&#xff0c;如何将Word文档转换为PDF呢&#xff1f;下面将介绍三种方法&#xff0c;相信对你会有所帮助。 一、记灵在线工具 首先&#xff0c;在浏览器中打开记灵在线工具的网…

Spring+SpringMVC+JdbcTemplate小Demo

项目目录结构 创建mavenWeb项目 pom文件 spring依赖、spring-web依赖、spring-webmvc依赖、spring-test、junit依赖 servlet依赖、jsp依赖、jstl、standard依赖 jackson的core和databind和annotations依赖、fastjson依赖、 文件上传的commons-fileupload和commons-io依赖 日志c…

图片修补 EdgeConnect 论文的阅读与翻译:生成边缘轮廓先验,再填补缺失内容

本文将要介绍的论文就是&#xff1a;EdgeConnect: Generative Image Inpainting with Adversarial Edge Learning&#xff0c;因为知乎在&#xff08;2019-02-02&#xff09;前&#xff0c;缺少详细介绍这篇论文的文章&#xff0c;而我最近需要复现它&#xff0c;所以顺便在这里…

消息重试框架 Spring-Retry 和 Guava-Retry

一 重试框架之Spring-Retry 1.Spring-Retry的普通使用方式 2.Spring-Retry的注解使用方式 二 重试框架之Guava-Retry 总结 图片 一 重试框架之Spring-Retry Spring Retry 为 Spring 应用程序提供了声明性重试支持。它用于Spring批处理、Spring集成、Apache Hadoop(等等)。…

智能应急疏散系统在公共建筑中的的应用

安科瑞 华楠 摘 要&#xff1a;随着大型公共建筑物的不断增多&#xff0c;其所产生的各种建筑安全隐患问题也在逐渐加剧&#xff0c;一旦出现火灾险情&#xff0c;要想从公共建筑中安全的脱离出来&#xff0c;其难度也是可想而知。因此&#xff0c;这就需要在进行公共建筑设计时…

Java打怪升级路线的相关知识

第一关:JavaSE阶段 1、计算机基础 2、java入门学习 3、java基础语法 4、流程控制和方法 5、数组 6、面向对象编程 7、异常 8、常用类 9、集合框架 10、IO 11、多线程 12、GUI编程 13、网络编程 14、注解与反射 15、JUC编程 16、JVM探究 17、23种设计模式 18、数据结构与算法 1…