GIMP-ML/gimp-plugins/PD-Denoising-pytorch/denoiser.py
2020-09-27 08:50:41 +05:30

139 lines
6.4 KiB
Python

import cv2
import os
import argparse
import glob
import numpy as np
import torch
import torch.nn as nn
from torch.autograd import Variable
from models import *
from utils import *
from PIL import Image
import scipy.io as sio
#the limitation range of each type of noise level: [0]Gaussian [1]Impulse
limit_set = [[0,75], [0, 80]]
def img_normalize(data):
return data/255.
def denoiser(Img, c, pss, model, model_est, opt, cFlag):
w, h, _ = Img.shape
Img = pixelshuffle(Img, pss)
Img = img_normalize(np.float32(Img))
noise_level_list = np.zeros((2 * c,1)) #two noise types with three channels
if opt.cond == 0: #if we use the ground truth of noise for denoising, and only one single noise type
noise_level_list = np.array(opt.test_noise_level)
elif opt.cond == 2: #if we use an external fixed input condition for denoising
noise_level_list = np.array(opt.ext_test_noise_level)
#Clean Image Tensor for evaluation
ISource = np2ts(Img)
# noisy image and true residual
if opt.real_n == 0 and opt.spat_n == 0: #no spatial noise setting, and synthetic noise
noisy_img = generate_comp_noisy(Img, np.array(opt.test_noise_level) / 255.)
if opt.color == 0:
noisy_img = np.expand_dims(noisy_img[:,:,0], 2)
elif opt.real_n == 1 or opt.real_n == 2: #testing real noisy images
noisy_img = Img
elif opt.spat_n == 1:
noisy_img = generate_noisy(Img, 2, 0, 20, 40)
INoisy = np2ts(noisy_img, opt.color)
INoisy = torch.clamp(INoisy, 0., 1.)
True_Res = INoisy - ISource
if torch.cuda.is_available() and not cFlag:
ISource, INoisy, True_Res = Variable(ISource.cuda(),volatile=True), Variable(INoisy.cuda(),volatile=True), Variable(True_Res.cuda(),volatile=True)
else:
ISource, INoisy, True_Res = Variable(ISource,volatile=True), Variable(INoisy,volatile=True), Variable(True_Res,volatile=True)
if opt.mode == "MC":
# obtain the corrresponding input_map
if opt.cond == 0 or opt.cond == 2: #if we use ground choose level or the given fixed level
#normalize noise leve map to [0,1]
noise_level_list_n = np.zeros((2*c, 1))
print(c)
for noise_type in range(2):
for chn in range(c):
noise_level_list_n[noise_type * c + chn] = normalize(noise_level_list[noise_type * 3 + chn], 1, limit_set[noise_type][0], limit_set[noise_type][1]) #normalize the level value
#generate noise maps
noise_map = np.zeros((1, 2 * c, Img.shape[0], Img.shape[1])) #initialize the noise map
noise_map[0, :, :, :] = np.reshape(np.tile(noise_level_list_n, Img.shape[0] * Img.shape[1]), (2*c, Img.shape[0], Img.shape[1]))
NM_tensor = torch.from_numpy(noise_map).type(torch.FloatTensor)
NM_tensor = Variable(NM_tensor.cuda(),volatile=True)
#use the estimated noise-level map for blind denoising
elif opt.cond == 1: #if we use the estimated map directly
NM_tensor = torch.clamp(model_est(INoisy), 0., 1.)
if opt.refine == 1: #if we need to refine the map before putting it to the denoiser
NM_tensor_bundle = level_refine(NM_tensor, opt.refine_opt, 2*c, cFlag) #refine_opt can be max, freq and their average
NM_tensor = NM_tensor_bundle[0]
noise_estimation_table = np.reshape(NM_tensor_bundle[1], (2 * c,))
if opt.zeroout == 1:
NM_tensor = zeroing_out_maps(NM_tensor, opt.keep_ind)
Res = model(INoisy, NM_tensor)
elif opt.mode == "B":
Res = model(INoisy)
Out = torch.clamp(INoisy-Res, 0., 1.) #Output image after denoising
#get the maximum denoising result
max_NM_tensor = level_refine(NM_tensor, 1, 2*c, cFlag)[0]
max_Res = model(INoisy, max_NM_tensor)
max_Out = torch.clamp(INoisy - max_Res, 0., 1.)
max_out_numpy = visual_va2np(max_Out, opt.color, opt.ps, pss, 1, opt.rescale, w, h, c)
del max_Out
del max_Res
del max_NM_tensor
if (opt.ps == 1 or opt.ps == 2) and pss!=1: #pixelshuffle multi-scale
#create batch of images with one subsitution
mosaic_den = visual_va2np(Out, opt.color, 1, pss, 1, opt.rescale, w, h, c)
out_numpy = np.zeros((pss ** 2, c, w, h))
#compute all the images in the ps scale set
for row in range(pss):
for column in range(pss):
re_test = visual_va2np(Out, opt.color, 1, pss, 1, opt.rescale, w, h, c, 1, visual_va2np(INoisy, opt.color), [row, column])/255.
#cv2.imwrite(os.path.join(opt.out_dir,file_name + '_%d_%d.png' % (row, column)), re_test[:,:,::-1]*255.)
re_test = np.expand_dims(re_test, 0)
if opt.color == 0: #if gray image
re_test = np.expand_dims(re_test[:, :, :, 0], 3)
re_test_tensor = torch.from_numpy(np.transpose(re_test, (0,3,1,2))).type(torch.FloatTensor)
if torch.cuda.is_available() and not cFlag:
re_test_tensor = Variable(re_test_tensor.cuda(),volatile=True)
else:
re_test_tensor = Variable(re_test_tensor, volatile=True)
re_NM_tensor = torch.clamp(model_est(re_test_tensor), 0., 1.)
if opt.refine == 1: #if we need to refine the map before putting it to the denoiser
re_NM_tensor_bundle = level_refine(re_NM_tensor, opt.refine_opt, 2*c, cFlag) #refine_opt can be max, freq and their average
re_NM_tensor = re_NM_tensor_bundle[0]
re_Res = model(re_test_tensor, re_NM_tensor)
Out2 = torch.clamp(re_test_tensor - re_Res, 0., 1.)
out_numpy[row*pss+column,:,:,:] = Out2.data.cpu().numpy()
del Out2
del re_Res
del re_test_tensor
del re_NM_tensor
del re_test
out_numpy = np.mean(out_numpy, 0)
out_numpy = np.transpose(out_numpy, (1,2,0)) * 255.0
elif opt.ps == 0 or pss==1: #other cases
out_numpy = visual_va2np(Out, opt.color, 0, 1, 1, opt.rescale, w, h, c)
out_numpy = out_numpy.astype(np.float32) #details
max_out_numpy = max_out_numpy.astype(np.float32) #background
#merging the details and background to balance the effect
k = opt.k
merge_out_numpy = (1-k)*out_numpy + k*max_out_numpy
merge_out_numpy = merge_out_numpy.astype(np.float32)
return merge_out_numpy