├── README.md ├── LICENSE ├── discriminator.py └── generator.py /README.md: -------------------------------------------------------------------------------- 1 | # Image-Super-Resolution-Using-C-in-C-GAN [ work in progress ..... :P ] 2 | This is an implementation of the CVPR 2018 paper titled - " Unsupervised Image SuperResolution using Cycle-In-Cycle GAN" 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Pranay Mukherjee 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /discriminator.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Necessary library imports 3 | 4 | ''' 5 | 6 | import keras 7 | from keras.layers import Conv2D, BatchNormalization, Activation, Input, Flatten 8 | from keras.model import Models 9 | 10 | def discriminator(type): 11 | 12 | input_layer = Input(shape=(256, 256, 3), name='input_layer') 13 | 14 | conv_1 = Conv2D(filters=64, kernel_size=(4, 4), strides=(type, type), activation='relu')(input_layer) 15 | 16 | conv_2 = Conv2D(filters=128, kernel_size=(4, 4), strides=(type, type))(conv_1) 17 | conv_2 = BatchNormalization(axis=-1)(conv_2) 18 | conv_2 = Activation('relu')(conv_2) 19 | 20 | conv_3 = Conv2D(filters=256, kernel_size=(4, 4), strides=(type, type))(conv_2) 21 | conv_3 = BatchNormalization(axis=-1)(conv_3) 22 | conv_3 =Activation('relu')(conv_3) 23 | 24 | conv_4 = Conv2D(filters=512, kernel_size=(4, 4), strides=(1, 1))(conv_3) 25 | conv_4 = BatchNormalization(axis=-1)(conv_4) 26 | conv_4 = Activation('relu')(conv_4) 27 | 28 | conv_5 = Conv2D(filters=1, kernel_size=(4, 4),strides=(1, 1))(conv_4) 29 | 30 | output = Flatten()(conv_5) 31 | 32 | model = Model(inputs = input_layer, outputs = output) 33 | 34 | return model 35 | 36 | 37 | -------------------------------------------------------------------------------- /generator.py: -------------------------------------------------------------------------------- 1 | import keras 2 | from keras.layers import Conv2D, Input, merge 3 | from keras.model import Model 4 | 5 | def residual_block(input_tensor): 6 | 7 | ''' 8 | This is code for the Residual block present in 9 | generators of the proposed network. The Residual 10 | Block consists of 2 Conv2D layers and a merge layer 11 | for adding the output of the second Conv2D layer to 12 | the input tensor of the residual block. 13 | 14 | ''' 15 | 16 | conv_1_1 = Conv2D(filters=64, kernel_size=(3, 3), strides=(1, 1), 17 | padding='same', name='residual_1')(input_tensor) 18 | 19 | conv_1_2 = Conv2D(filters=64, kernel_size=(3, 3), strides=(1, 1), 20 | padding='same', name='residual_2')(conv_1_1) 21 | 22 | sum_tensor = merge([input_tensor, conv_1_2], mode='sum', name='residual_summation') 23 | 24 | return sum_tensor 25 | 26 | 27 | 28 | def generator(generator_type): 29 | 30 | ''' 31 | This is the code for the Generators G1, G2, G3 as per the paper. 32 | Although the generators share the same architecture ,there is a 33 | little variation in the architectures of the [G1, G2] and [G3]. 34 | However all the are made of 3 Conv2D layers on the either side of 35 | the network and contain 6 residual blocks in between. 36 | 37 | ''' 38 | 39 | input_layer = Input(shape(32,32,1),name='LowResInput') 40 | conv_1 = Conv2D(filters=64, kernel_size=(7, 7), strides=(1, 1), 41 | padding='same', name='first_conv')(input_layer) 42 | 43 | ''' 44 | For G3, the kernel size and the stride is (4, 4) and (2, 2) 45 | respectively. For G1 and G2, the kernel size and the stride 46 | is (3, 3) and (1, 1) 47 | 48 | ''' 49 | 50 | if(generator_type==3): 51 | 52 | k, s = 4, 2 53 | 54 | else: 55 | 56 | k, s = 3, 1 57 | 58 | 59 | conv_2 = Conv2D(filters=64, kernel_size=(k, k), strides=(s, s), 60 | padding='same', name='second_conv')(conv_1) 61 | conv_3 = Conv2D(filters=64, kernel_size=(k, k), strides=(s, s), 62 | padding='same', name='third_conv')(conv_2) 63 | 64 | input_tensor = conv_3 65 | 66 | ''' 67 | Residual blocks added for 6 consecutive times 68 | 69 | ''' 70 | 71 | for i in range(6): 72 | 73 | residual_output = residual_block(input_tensor) 74 | input_tensor = residual_output 75 | 76 | conv_4 = Conv2D(filters=64, kernel_size=(3, 3), strides=(1, 1), 77 | padding='same', name='fourth_conv')(residual_output) 78 | 79 | conv_5 = Conv2D(filters=64, kernel_size=(3, 3), strides=(1, 1), 80 | padding='same', name='fifth_conv')(conv_4) 81 | 82 | output_generator = Conv2D(filters=3, kernel_size=(7, 7), strides=(1, 1), 83 | padding='same', name='generator_output')(conv_5) 84 | 85 | model = Model(inputs=input_layer, outputs=output_generator) 86 | 87 | return model 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | --------------------------------------------------------------------------------