AI绘画:GauGAN实现图像从分割图到真实图像的转换
立即解锁
发布时间: 2025-09-02 00:32:20 阅读量: 4 订阅数: 6 AIGC 

### AI绘画:GauGAN实现图像从分割图到真实图像的转换
#### 1. 选择GauGAN的原因
由于目前没有新的生成对抗网络(GAN)架构,我们不打算实现iGAN,而是选择实现GauGAN。GauGAN由英伟达(Nvidia)开发,英伟达在GAN领域投入了大量资源,取得了多项突破,如用于生成高分辨率图像的ProgressiveGAN和用于生成高保真面部图像的StyleGAN。而且,英伟达倾向于将其软件代码开源,还搭建了网页(http://nvidia-research-mingyuliu.com/gaugan/)展示GauGAN,它能根据分割图生成逼真的风景照片。
#### 2. pix2pixHD简介
GauGAN以pix2pixHD为基础并添加了新特性。pix2pixHD是pix2pix的升级版,可生成高清图像。虽然我们不使用高清数据集,但了解pix2pixHD的高层架构也很有必要。
- **生成器架构**:为了生成高分辨率图像,pix2pixHD使用两个不同分辨率的生成器,即粗粒度生成器G1和细粒度生成器G2。G1以一半的图像分辨率工作,输入和目标图像会被下采样到一半分辨率。训练好G1后,再将其与在全图像尺度上工作的G2一起训练。G1的编码器输出与G1的特征拼接后输入到G2的解码器部分,以生成高分辨率图像,这种设置也称为从粗到细的生成器。
- **判别器架构**:pix2pixHD使用三个在不同图像尺度上操作的PatchGAN判别器。
- **损失函数**:采用了一种新的损失函数——特征匹配损失,用于匹配真实图像和生成图像之间的层特征,在风格迁移中,会使用预训练的VGG进行特征提取并优化风格特征。
#### 3. 空间自适应归一化(SPADE)
GauGAN的主要创新点是一种用于分割图的层归一化方法——空间自适应归一化(SPADE)。在深入了解SPADE之前,我们需要先了解网络输入的格式——语义分割图。
##### 3.1 独热编码的分割掩码
我们使用facades数据集来训练GauGAN。在之前的实验中,分割图以RGB图像中的不同颜色编码,这种表示方式虽然便于人类理解,但对神经网络学习帮助不大,因为颜色没有语义含义。更好的方法是使用独热编码,当某个像素存在对象时,该像素对应的掩码标签为1,否则为0,即把分割图中的标签编码为形状为(H, W, 类别数量)的分割掩码。
由于之前章节使用的facades数据集是JPEG编码,JPEG编码在压缩过程中会去除一些对视觉不太重要的信息,导致即使属于同一类别的像素也可能有不同的值,无法将JPEG图像中的颜色映射到类别。因此,我们获取原始数据集并创建了一个新数据集,每个样本包含三种不同的图像文件类型:
- JPEG:真实照片
- PNG:使用RGB颜色的分割图
- BMP:使用类别标签的分割图
在图像加载和预处理时,我们会加载这三个文件,并将BMP文件转换为独热编码的分割掩码。以下是文件加载函数的代码:
```python
def load(image_file):
def load_data(image_file):
jpg_file = image_file.numpy().decode("utf-8")
bmp_file = jpg_file.replace('.jpg','.bmp')
png_file = jpg_file.replace('.jpg','.png')
image = np.array(Image.open(jpg_file))/127.5 - 1
map = np.array(Image.open(png_file))/127.5 - 1
labels = np.array(Image.open(bmp_file), dtype=np.uint8)
h, w, _ = image.shape
n_class = 12
mask = np.zeros((h, w, n_class), dtype=np.float32)
for i in range(n_class):
one_hot[labels==i, i] = 1
return map, image, mask
[mask, image, label] = tf.py_function(load_data, [image_file], [tf.float32, tf.float32, tf.float32])
```
##### 3.2 实现SPADE
实例归一化在图像生成中很流行,但它容易消除分割掩码的语义含义。例如,当输入图像只有一个分割标签(如整个图像都是天空)时,经过卷积层后输出值均匀,实例归一化会使归一化后的激活值变为零,导致语义信息丢失。
为了解决这个问题,SPADE在分割掩码限定的局部区域进行归一化,而不是对整个掩码进行归一化。以下是实现SPADE的TensorFlow自定义层代码:
```python
class SPADE(layers.Layer):
def __init__(self, filters, epsilon=1e-5):
super(SPADE, self).__init__()
self.epsilon = epsilon
self.conv = layers.Conv2D(128, 3, padding='same', activation='relu')
self.conv_gamma = layers.Conv2D(filters, 3, padding='same')
self.conv_beta = layers.Conv2D(filters, 3, padding='same')
def build(self, input_shape):
self.resize_shape = input_shape[1:3]
def call(self, input_tensor, raw_mask):
mask = tf.image.resize(raw_mask, self.resize_shape, method='nearest')
x = self.conv(mask)
gamma = self.conv_gamma(x)
beta = self.conv_beta(x)
mean, var = tf.nn.moments(input_tensor, axes=(0,1,2), keepdims=True)
std = tf.sqrt(var + self.epsilon)
normalized = (input_tensor - mean)/std
output = gamma * normalized + beta
return output
```
##### 3.3 将SPADE插入残差块
GauGAN的生成器使用残差块,我们需要将SPADE插入残差块。SPADE残差块的基本构建块是SPADE - ReLU - Conv层,每个SPADE接收两个输入:前一层的激活值和语义分
0
0
复制全文
相关推荐









