如何使用Python对图片进行纹理生成

1. 简介

在计算机视觉领域,纹理生成是一个重要的任务。在这里,本文将介绍如何使用Python对图片进行纹理生成。纹理生成是指从一张图片中合成出随机的、看上去像是真实的纹理。这个纹理可以被用于一些应用中,比如游戏或者电影中的贴图。

2. 相关概念

2.1 GAN

GAN是生成对抗网络(Generative Adversarial Networks)的简称。GAN的运行过程是通过两个深度神经网络进行博弈:生成器(generator)和判别器(discriminator)。生成器的目的是伪造和真实图像相似的图像,判别器的目的是判断一个图像是真是假。具体地说,判别器会返回一个值,用于表示给定的图像是真实图像的概率。而生成器会尝试生成更加真实的图像,使得判别器的预测结果越接近1越好。

GAN的训练过程是通过反向传播算法进行的。也就是说,首先在真实图像中挑选一部分图像进行训练,将生成器和判别器网络进行构建;然后,每次训练的过程中,先让判别器判断一批(通常为32张)图像的真假;接着,让生成器尝试生成一批与真实图像相似的图像,再让判别器判断这批图像的真假,如此交替进行,直至可以输出非常真实的图像。

2.2 VAE

VAE是变分自编码器(Variational Auto-Encoder)的简称。它是一种神经网络模型,通常用于对数据的压缩和提取特征。

3. 材料准备

在本文中,我们将使用GAN来生成纹理。具体来说,我们将使用keras-tqdm、keras和tensorflow2.0。

在使用keras-tqdm的构建进度条时,需要安装相应的依赖。可以使用以下命令进行安装:

!pip install keras-tqdm

4. 图片预处理

在本文中,我们将使用python的imageio库来读取图片,并使用Pillow库来缩放图像。以下是如何使用文件路径加载图像:

import imageio

import numpy as np

from PIL import Image

def load_image(path):

img = Image.open(path)

img = np.array(img)

return img

由于GAN模型只能处理较小的图像,为了将图像调整到合适的大小,可以使用Pillow库的resize方法:

from PIL import Image

def resize_image(img, size):

img = Image.fromarray(img)

img = img.resize(size)

img = np.array(img)

return img

5. 纹理生成器的构建

在本文中,我们将使用DCGAN(深度卷积生成对抗网络, Deep Convolutional Generative Adversarial Networks)网络来构建纹理生成器。其大致结构如下:

具体来讲,主要由以下部分组成:

一个全连接层,用于从输入的潜在空间 z 生成尺寸为7 * 7 * 256的张量;

后续是一系列反卷积操作、批量归一化操作和ReLU激活函数,用于将尺寸缩放成28 * 28 * 1;

最后一个反卷积操作用于将尺寸调整到所需的大小(通常是64 * 64 * 1)。

下面是我们实现DCGAN的生成器的代码:

from keras.models import Sequential

from keras.layers import Dense, Reshape, Conv2DTranspose, BatchNormalization, ReLU

def build_generator():

generator = Sequential()

# 一对全连接层将潜在空间映射到尺寸为7 * 7 * 256的张量上

generator.add(Dense(units=7*7*256, activation='relu', input_shape=(100,)))

generator.add(Reshape(target_shape=(7, 7, 256)))

generator.add(Conv2DTranspose(filters=128, kernel_size=(5,5), strides=(1,1), padding='SAME',

activation=None, use_bias=False))

generator.add(BatchNormalization())

generator.add(ReLU())

# 这里使用反卷积操作将尺寸缩放成28 * 28 * 1

generator.add(Conv2DTranspose(filters=64, kernel_size=(5,5), strides=(2,2), padding='SAME',

activation=None, use_bias=False))

generator.add(BatchNormalization())

generator.add(ReLU())

# 最后一个反卷积操作将尺寸调整到64 * 64 * 1

generator.add(Conv2DTranspose(filters=1, kernel_size=(5,5), strides=(2,2), padding='SAME',

activation='tanh', use_bias=False))

return generator

6. 判别器的构建

判别器的构建与生成器类似,主要由以下部分组成:

由一系列卷积层、批量归一化层和LeakyReLU激活函数组成,用于逐步缩小输入图像的尺寸;

最后是一个全连接层,用于生成网络输出值(0到1之间的概率值)。

以下是我们实现的判别器的代码:

from keras.layers import Conv2D, LeakyReLU, Flatten

def build_discriminator():

discriminator = Sequential()

# 这一层卷积层负责将输入缩小到尺寸为14 * 14 * 64

discriminator.add(Conv2D(filters=64, kernel_size=(5,5), strides=(2,2), padding='SAME',

activation=None, input_shape=(64, 64, 1)))

discriminator.add(LeakyReLU(alpha=0.2))

# 接下来的几层都用卷积+批量归一化+LeakyReLU,将尺寸不断缩小

discriminator.add(Conv2D(filters=128, kernel_size=(5,5), strides=(2,2), padding='SAME',

activation=None))

discriminator.add(BatchNormalization())

discriminator.add(LeakyReLU(alpha=0.2))

discriminator.add(Conv2D(filters=256, kernel_size=(5,5), strides=(2,2), padding='SAME',

activation=None))

discriminator.add(BatchNormalization())

discriminator.add(LeakyReLU(alpha=0.2))

# 最后一个全连接层,输出0到1之间的概率值

discriminator.add(Flatten())

discriminator.add(Dense(units=1, activation='sigmoid'))

return discriminator

7. GAN模型的合成

现在看一下我们的GAN是如何运作的:由于我们的目的是生成纹理,因此我们将生成器的输出作为最终输出。我们使用生成器来生成图像,并且通过将判别器应用于生成器输出的图像,检测它是否“真实”。因此,我们需要同时训练判别器和生成器。

具体来说,首先训练判别器。在这个阶段,我们将使用????给定的真实输入图像,以及从生成器中生成的虚假输入图像,同时训练判别器。目标是最小化训练数据和生成器生成的数据之间的“距离”。

在判别器和生成器分别训练完之后,我们可以将它们合并在一起,通过在预测中使用生成器,来让GAN生成纹理。这时我们可以使用训练好的全局模型获取真实的纹理数据。

下面是我们实现的GAN的代码:

from keras.optimizers import Adam

# discriminator的优化器和损失函数

dis_opt = Adam(lr=0.0002, beta_1=0.5, decay=8e-8)

discriminator.compile(loss='binary_crossentropy', optimizer=dis_opt, metrics=['accuracy'])

# 需要训练的参数的数量,为了训练生成器

discriminator.trainable = False

# 生成器和GAN的优化器

gen_opt = Adam(lr=0.0002, beta_1=0.5, decay=8e-8)

gan.compile(loss='binary_crossentropy', optimizer=gen_opt, metrics=['accuracy'])

8. 训练模型

在准备好数据、定义模型,并且设置好优化器和损失函数之后,现在可以直接训练模型并查看训练进程的实时动态了。

在这里,我们将G和D迭代数目都设置为10000,并使用Python的tqdm("")函数实现一个进度条,可以精细地跟踪训练的进度:

from tqdm import tqdm

def train(generator, discriminator, gan, iterations, batch_size, sample_interval):

# 加载数据

X_train = load_image('path_to_image')

X_train = resize_image(X_train, size=(64, 64))

X_train = np.expand_dims(X_train, axis=0)

X_train = (X_train.astype(np.float32) / 127.5) - 1.

# 指定标准分布的大小 (i.e. : latent space vector -> noise)

sample_size = 100

# 迭代数

for iteration in tqdm(range(iterations)):

# 从真实图像中随机选择一些数据

idx = np.random.randint(0, X_train.shape[0], batch_size)

real_images = X_train[idx]

# 生成噪音数据

noise = np.random.normal(0, 1, (batch_size, sample_size))

# 由生成器产生假图像

generated_images = generator.predict(noise)

# 把所有的数据堆在一起

x_combined_batch = np.concatenate((real_images, generated_images))

y_combined_batch = np.concatenate((np.ones((batch_size, 1)), np.zeros((batch_size, 1))))

# 通过随机梯度下降法(SGD)训练判别器

d_loss = discriminator.train_on_batch(x_combined_batch, y_combined_batch)

# 再次生成噪声数据,并将其与真实标签互换。请注意,我们不使用样本梯度之外的梯度来更新生成器权重,因此 discriminator.trainable 设置为 False

noise = np.random.normal(0, 1, (batch_size, sample_size))

# 误差数据,标签数据

y_fake = np.ones((batch_size, 1))

# 让生成器学习纹理

gan_loss = gan.train_on_batch(noise, y_fake)

# 打印损失和精度

if (iteration + 1) % sample_interval == 0:

print(f"Epoch: {iteration + 1}, GAN Loss: {gan_loss[0]}, Discriminator Loss: {d_loss[0]}")

总结

在本文中,我们介绍了如何使用GAN来生成纹理。我们实现了一个深度卷积生成器网络和一个深度卷积判别器网络,并使用这两个网络,并结合GAN来训练和评估参数,实现了纹理生成。我们还使用tqdm库来实现了一个进度条,精细地跟踪了我们的GAN的训练进程。

后端开发标签