File size: 14,166 Bytes
db5513e
 
905cd18
 
 
 
 
 
db5513e
 
 
 
 
 
 
 
 
 
 
 
905cd18
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
db5513e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
905cd18
 
 
 
 
 
 
 
db5513e
905cd18
db5513e
 
 
 
905cd18
 
 
 
db5513e
905cd18
 
db5513e
905cd18
 
 
 
 
 
 
 
db5513e
 
 
 
 
905cd18
db5513e
905cd18
db5513e
 
 
905cd18
db5513e
905cd18
 
 
 
 
 
 
 
db5513e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
905cd18
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
import math
from random import choice, choices, randint

import cv2
import numpy as np
from PIL import Image
from torch.utils.data.dataset import Dataset

from utils import USMSharp_npy, cvtColor, preprocess_input

from .degradations import (circular_lowpass_kernel, random_add_gaussian_noise,
                           random_add_poisson_noise, random_mixed_kernels)
from .transforms import augment, paired_random_crop

def cv_show(image):
    image = np.array(image)
    image = cv2.resize(image, (256, 128), interpolation=cv2.INTER_CUBIC)
    cv2.imshow('image', image)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

def get_new_img_size(width, height, img_min_side=600):
    if width <= height:
        f = float(img_min_side) / width
        resized_height = int(f * height)
        resized_width = int(img_min_side)
    else:
        f = float(img_min_side) / height
        resized_width = int(f * width)
        resized_height = int(img_min_side)

    return resized_width, resized_height

class SRGANDataset(Dataset):
    def __init__(self, train_lines, lr_shape, hr_shape):
        super(SRGANDataset, self).__init__()

        self.train_lines    = train_lines
        self.train_batches  = len(train_lines)

        self.lr_shape       = lr_shape
        self.hr_shape       = hr_shape
        self.scale          = int(hr_shape[0]/lr_shape[0])
        self.usmsharp       = USMSharp_npy()
        # 第一次滤波的参数
        self.blur_kernel_size = 21
        self.kernel_list    = ['iso', 'aniso', 'generalized_iso', 'generalized_aniso', 'plateau_iso', 'plateau_aniso']
        self.kernel_prob    = [0.45, 0.25, 0.12, 0.03, 0.12, 0.03]
        self.sinc_prob      = 0.1
        self.blur_sigma     = [0.2, 3]
        self.betag_range    = [0.5, 4]
        self.betap_range    = [1, 2]
        # 第二次滤波的参数
        self.blur_kernel_size2 = 21
        self.kernel_list2    = ['iso', 'aniso', 'generalized_iso', 'generalized_aniso', 'plateau_iso', 'plateau_aniso']
        self.kernel_prob2    = [0.45, 0.25, 0.12, 0.03, 0.12, 0.03]
        self.sinc_prob2      = 0.1
        self.blur_sigma2     = [0.2, 3]
        self.betag_range2    = [0.5, 4]
        self.betap_range2    = [1, 2]
        # 最后的sinc滤波
        self.final_sinc_prob = 0.8
        # 卷积核大小从7到21分布
        self.kernel_range    = [2 * v + 1 for v in range(3, 11)]
        # 使用脉冲张量进行卷积不会产生模糊效果
        self.pulse_tensor    = np.zeros(shape=[21, 21], dtype='float32')  
        self.pulse_tensor[10, 10] = 1
        # 第一次退化的参数
        self.resize_prob         = [0.2, 0.7, 0.1]  # up, down, keep
        self.resize_range        = [0.15, 1.5]
        self.gaussian_noise_prob = 0.5
        self.noise_range         = [1, 30]
        self.poisson_scale_range = [0.05, 3]
        self.gray_noise_prob     = 0.4
        self.jpeg_range          = [30, 95]

        # 第二次退化的参数
        self.second_blur_prob    = 0.8
        self.resize_prob2        = [0.3, 0.4, 0.3]  # up, down, keep
        self.resize_range2       = [0.3, 1.2]
        self.gaussian_noise_prob2= 0.5
        self.noise_range2        = [1, 25]
        self.poisson_scale_range2= [0.05, 2.5]
        self.gray_noise_prob2    = 0.4
        self.jpeg_range2         = [30, 95]

    def __len__(self):
        return self.train_batches

    def __getitem__(self, index):
        index = index % self.train_batches

        image_origin = Image.open(self.train_lines[index].split()[0])
        lq, gt = self.get_random_data(image_origin, self.hr_shape)

        gt = np.transpose(preprocess_input(np.array(gt, dtype=np.float32), [0.5,0.5,0.5], [0.5,0.5,0.5]), [2,0,1])
        lq = np.transpose(preprocess_input(np.array(lq, dtype=np.float32), [0.5,0.5,0.5], [0.5,0.5,0.5]), [2,0,1])
        
        return lq, gt

    def rand(self, a=0, b=1):
        return np.random.rand()*(b-a) + a

    def get_random_data(self, image, input_shape):
        #------------------------------#
        #   读取图像并转换成RGB图像
        #   cvtColor将np转Image
        #------------------------------#
        image   = cvtColor(image)
        #------------------------------#
        #   获得图像的高宽与目标高宽
        #------------------------------#
        iw, ih  = image.size
        h, w    = input_shape

        scale = min(w/iw, h/ih)
        nw = int(iw*scale)
        nh = int(ih*scale)
        dx = (w-nw)//2
        dy = (h-nh)//2

        #---------------------------------#
        #   将图像多余的部分加上灰条
        #---------------------------------#
        image       = image.resize((nw,nh), Image.BICUBIC)
        new_image   = Image.new('RGB', (w,h), (128,128,128))
        new_image.paste(image, (dx, dy))
        image       = np.array(new_image, np.float32)
        
        rotate = self.rand()<.5
        if rotate: 
            angle = np.random.randint(-15,15)
            a,b = w/2,h/2
            M = cv2.getRotationMatrix2D((a,b),angle,1)
            image = cv2.warpAffine(np.array(image), M, (w,h), borderValue=[128,128,128]) 

        # ------------------------ 生成卷积核以进行第一次退化处理 ------------------------ #
        kernel_size = choice(self.kernel_range)
        if np.random.uniform() < self.sinc_prob:
            # 此sinc过滤器设置适用于[7,21]范围内的内核
            if kernel_size < 13:
                omega_c = np.random.uniform(np.pi / 3, np.pi)
            else:
                omega_c = np.random.uniform(np.pi / 5, np.pi)
            kernel = circular_lowpass_kernel(omega_c, kernel_size, pad_to=False)
        else:
            kernel = random_mixed_kernels(
                self.kernel_list,
                self.kernel_prob,
                kernel_size,
                self.blur_sigma,
                self.blur_sigma, [-math.pi, math.pi],
                self.betag_range,
                self.betap_range,
                noise_range=None)
        # pad kernel
        pad_size = (21 - kernel_size) // 2
        kernel = np.pad(kernel, ((pad_size, pad_size), (pad_size, pad_size)))
        kernel = kernel.astype(np.float32)
        # ------------------------ 生成卷积核以进行第二次退化处理 ------------------------ #
        kernel_size = choice(self.kernel_range)
        if np.random.uniform() < self.sinc_prob2:
            if kernel_size < 13:
                omega_c = np.random.uniform(np.pi / 3, np.pi)
            else:
                omega_c = np.random.uniform(np.pi / 5, np.pi)
            kernel2 = circular_lowpass_kernel(omega_c, kernel_size, pad_to=False)
        else:
            kernel2 = random_mixed_kernels(
                self.kernel_list2,
                self.kernel_prob2,
                kernel_size,
                self.blur_sigma2,
                self.blur_sigma2, [-math.pi, math.pi],
                self.betag_range2,
                self.betap_range2,
                noise_range=None)
        # pad kernel
        pad_size = (21 - kernel_size) // 2
        kernel2 = np.pad(kernel2, ((pad_size, pad_size), (pad_size, pad_size)))
        kernel2 = kernel2.astype(np.float32)
        # ----------------------the final sinc kernel ------------------------- #
        if np.random.uniform() < self.final_sinc_prob:
            kernel_size = choice(self.kernel_range)
            omega_c = np.random.uniform(np.pi / 3, np.pi)
            sinc_kernel = circular_lowpass_kernel(omega_c, kernel_size, pad_to=21)
        else:
            sinc_kernel = self.pulse_tensor
        sinc_kernel = sinc_kernel.astype(np.float32)
        lq, gt      = self.feed_data(image, kernel, kernel2, sinc_kernel)

        return lq, gt

    def feed_data(self, img_gt, kernel1, kernel2, sinc_kernel):

        img_gt = np.array(img_gt, dtype=np.float32)
        # 对gt进行锐化
        img_gt = np.clip(img_gt / 255, 0, 1)
        gt     = self.usmsharp.filt(img_gt)
        [ori_w, ori_h, _] = gt.shape

        # ---------------------- 根据参数进行第一次退化 -------------------- #
        # 模糊处理
        out = cv2.filter2D(img_gt, -1, kernel1)
        # 随机 resize
        updown_type = choices(['up', 'down', 'keep'], self.resize_prob)[0]
        if updown_type == 'up':
            scale = np.random.uniform(1, self.resize_range[1])
        elif updown_type == 'down':
            scale = np.random.uniform(self.resize_range[0], 1)
        else:
            scale = 1
        mode = choice(['area', 'bilinear', 'bicubic'])
        if mode=='area':
            out = cv2.resize(out, (int(ori_h * scale), int(ori_w * scale)), interpolation=cv2.INTER_AREA)
        elif mode=='bilinear':
            out = cv2.resize(out, (int(ori_h * scale), int(ori_w * scale)), interpolation=cv2.INTER_LINEAR)
        else:
            out = cv2.resize(out, (int(ori_h * scale), int(ori_w * scale)), interpolation=cv2.INTER_CUBIC)

        # 灰度噪声
        gray_noise_prob = self.gray_noise_prob
        if np.random.uniform() < self.gaussian_noise_prob:
            out = random_add_gaussian_noise(
                out, sigma_range=self.noise_range, clip=True, rounds=False, gray_prob=gray_noise_prob)
        else:
            out = random_add_poisson_noise(
                out,
                scale_range=self.poisson_scale_range,
                gray_prob=gray_noise_prob,
                clip=True,
                rounds=False)

        # JPEG 压缩
        jpeg_p = np.random.uniform(low=self.jpeg_range[0], high=self.jpeg_range[1])
        jpeg_p = int(jpeg_p)
        out    = np.clip(out, 0, 1)

        encode_param = [int(cv2.IMWRITE_JPEG_QUALITY), jpeg_p]
        _, encimg = cv2.imencode('.jpg', out * 255., encode_param)
        out = np.float32(cv2.imdecode(encimg, 1))/255

        # ---------------------- 根据参数进行第一次退化 -------------------- #
        # 模糊
        if np.random.uniform() < self.second_blur_prob:
            out = cv2.filter2D(out, -1, kernel2)
        # 随机 resize
        updown_type = choices(['up', 'down', 'keep'], self.resize_prob2)[0]
        if updown_type == 'up':
            scale = np.random.uniform(1, self.resize_range2[1])
        elif updown_type == 'down':
            scale = np.random.uniform(self.resize_range2[0], 1)
        else:
            scale = 1
        mode = choice(['area', 'bilinear', 'bicubic'])
        if mode == 'area':
            out = cv2.resize(out, (int(ori_h / self.scale * scale), int(ori_w / self.scale * scale)), interpolation=cv2.INTER_AREA)
        elif mode == 'bilinear':
            out = cv2.resize(out, (int(ori_h / self.scale * scale), int(ori_w / self.scale * scale)), interpolation=cv2.INTER_LINEAR)
        else:
            out = cv2.resize(out, (int(ori_h / self.scale * scale), int(ori_w / self.scale * scale)), interpolation=cv2.INTER_CUBIC)
        # 灰度噪声
        gray_noise_prob = self.gray_noise_prob2
        if np.random.uniform() < self.gaussian_noise_prob2:
            out = random_add_gaussian_noise(
                out, sigma_range=self.noise_range2, clip=True, rounds=False, gray_prob=gray_noise_prob)
        else:
            out = random_add_poisson_noise(
                out,
                scale_range=self.poisson_scale_range2,
                gray_prob=gray_noise_prob,
                clip=True,
                rounds=False)

        # JPEG压缩+最后的sinc滤波器
        # 我们还需要将图像的大小调整到所需的尺寸。我们把[调整大小+sinc过滤器]组合在一起
        # 作为一个操作。
        # 我们考虑两个顺序。
        # 1. [调整大小+sinc filter] + JPEG压缩
        # 2. 2. JPEG压缩+[调整大小+sinc过滤]。
        # 根据经验,我们发现其他组合(sinc + JPEG + Resize)会引入扭曲的线条。
        if np.random.uniform() < 0.5:
            # resize back + the final sinc filter
            mode = choice(['area', 'bilinear', 'bicubic'])
            if mode == 'area':
                out = cv2.resize(out, (ori_h // self.scale, ori_w // self.scale), interpolation=cv2.INTER_AREA)
            elif mode == 'bilinear':
                out = cv2.resize(out, (ori_h // self.scale, ori_w // self.scale), interpolation=cv2.INTER_LINEAR)
            else:
                out = cv2.resize(out, (ori_h // self.scale, ori_w // self.scale), interpolation=cv2.INTER_CUBIC)

            out = cv2.filter2D(out, -1, sinc_kernel)
            # JPEG 压缩
            jpeg_p = np.random.uniform(low=self.jpeg_range[0], high=self.jpeg_range[1])
            jpeg_p = jpeg_p
            out    = np.clip(out, 0, 1)

            encode_param = [int(cv2.IMWRITE_JPEG_QUALITY), jpeg_p]
            _, encimg = cv2.imencode('.jpg', out * 255., encode_param)
            out = np.float32(cv2.imdecode(encimg, 1)) / 255
        else:
            # JPEG 压缩
            jpeg_p = np.random.uniform(low=self.jpeg_range[0], high=self.jpeg_range[1])
            jpeg_p = jpeg_p
            out = np.clip(out, 0, 1)

            encode_param = [int(cv2.IMWRITE_JPEG_QUALITY), jpeg_p]
            _, encimg = cv2.imencode('.jpg', out * 255., encode_param)
            out = np.float32(cv2.imdecode(encimg, 1)) / 255
            # resize back + the final sinc filter
            mode = choice(['area', 'bilinear', 'bicubic'])
            if mode == 'area':
                out = cv2.resize(out, (ori_h // self.scale, ori_w // self.scale),interpolation=cv2.INTER_AREA)
            elif mode == 'bilinear':
                out = cv2.resize(out, (ori_h // self.scale, ori_w // self.scale),interpolation=cv2.INTER_LINEAR)
            else:
                out = cv2.resize(out, (ori_h // self.scale, ori_w // self.scale),interpolation=cv2.INTER_CUBIC)
        lq = np.clip((out * 255.0), 0, 255)
        gt = np.clip((gt  * 255.0), 0, 255)
        return Image.fromarray(np.uint8(lq)), Image.fromarray(np.uint8(gt))

def SRGAN_dataset_collate(batch):
    images_l = []
    images_h = []
    for img_l, img_h in batch:
        images_l.append(img_l)
        images_h.append(img_h)
    return np.array(images_l), np.array(images_h)