遗传算法与深度学习实战(9)——使用遗传算法重建图像

遗传算法与深度学习实战(9)——使用遗传算法重建图像

    • 0. 前言
    • 1. 使用遗传算法重建图像
      • 1.1 用多边形绘制图像
    • 2. EvoLisa 项目
    • 3. 实现遗传算法复现 EvoLisa 项目
      • 3.1 基因构建
      • 3.2 构建解决方案
    • 小结
    • 系列链接

0. 前言

遗传算法应用于图像处理的最流行方式之一是用一组半透明多边形重建图像。在此过程中,可以获得图像处理方面的有用经验,并获得对进化过程的直观见解。在本节中,我们通过复现 EvoLisa 项目重建《蒙娜丽莎》图像。

1. 使用遗传算法重建图像

在图像处理中使用遗传算法的最流行示例之一是使用一组半透明的重叠形状重建给定的图像。除了获得图像处理经验的机会外,这些实验还为进化过程提供了直观的了解,并有可能使人们对视觉艺术以及图像分析和图像压缩的发展有更好的了解。在图像重建实验中以熟悉的图像(通常是著名的绘画或其一部分)作为参考。通过组合颜色和透明度不同的重叠形状(通常是多边形)来构造相似的图像。

1.1 用多边形绘制图像

要从头开始绘制图像,可以使用 PillowImageImageDraw 类:

image = Image.new('RGB', (width, height))
draw = ImageDraw.Draw(image, 'RGBA')

RGBRGBA 是mode参数的可选值。RGB 值表示每个像素三个 8 位二进制值——红色 (R),绿色 (G) 和蓝色 (B)。RGBA 值添加了第 48 位值 A,代表图形的 alpha (不透明度)级别。
可以使用 ImageDraw 类的多边形函数将多边形添加到图像中,以下语句将在图像上绘制一个三角形:

draw.polygon([(x1, y1), (x2, y2), (x3, y3)], (red, green, blue, alpha))

其中:

  • (x1, y1)(x2, y2)(x3, y3) 元组表示三角形的三个顶点。每个元组都包含图像内相应顶点的 xy 坐标
  • 红色,绿色和蓝色是 [0, 255] 范围内的整数值,每个值代表多边形相应颜色的强度
  • alpha[0, 255] 范围内的整数值,表示多边形的不透明度值(值越低意味着透明度越高)

要绘制具有更多顶点的多边形,需要向列表中添加更多 (xi, yi) 元组。我们可以通过这种方式添加多个多边形,所有多边形都绘制在同一图像上,并且可能彼此重叠:

多边形绘制

2. EvoLisa 项目

2008 年,Roger Johansson 展示了使用遗传算法用一组多边形绘制《蒙娜丽莎》的作品,下图展示了在演化后期取得的出色结果,优异的结果需要近一百万代才能演化出来。

在这里插入图片描述

EvoLisa 是一种生成建模的例子,算法的目标是模拟或复制某个过程的输出,近年来,生成建模迅速发展。利用 DEAP,能够轻松复现 EvoLisa 项目,但是我们需要以一种更复杂和结构化的方式思考如何编码基因序列。在 N 皇后和旅行商问题中,一个基因是列表中的一个单独元素,现在需要将一个基因视为列表中的一组子元素。每个子元素(基因)定义了一个多边形,一个个体有多个用于在画布上绘制多边形的基因。

3. 实现遗传算法复现 EvoLisa 项目

接下来,使用 DEAP 实现遗传算法复现 EvoLisa 项目。我们已经知道,获得良好的结果可能需要很长时间。虽然我们并不会完全复制以上结果,但我们需要了解如何创建复杂基因,为复杂项目的构建奠定基础。

3.1 基因构建

我们首先需要了解如何将一系列数字转换为表示绘制多边形的基因。下图概述了如何从序列中提取一组属性,并将其转换为多边形笔刷,其中前六个元素表示简单多边形(三角形)的三个点。之后的三个元素表示颜色,最后一个元素表示 alpha (透明度)。通过引入透明度,可以将画笔叠加在一起,产生更复杂的特征。

属性提取

在 N 皇后和旅行商问题中,基因序列中的每个属性表示一个单独的基因。但在 EvoLisa 中,一组属性的子集构成了一个表示绘图笔刷的单个基因。

3.2 构建解决方案

(1) 导入所需库,并加载图像:

import random
import numpy as npfrom deap import algorithms
from deap import base
from deap import creator
from deap import toolsimport os
import cv2
import urllib.request
import matplotlib.pyplot as plt
from IPython.display import clear_outputdef load_target_image(image_url, color=True, size=None):image_path = "target_image"    urllib.request.urlretrieve(image_url,image_path)if color:target = cv2.imread(image_path, cv2.IMREAD_COLOR)# Switch from bgr to rgbtarget = cv2.cvtColor(target, cv2.COLOR_BGR2RGB)else:target = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE)if size:# Only resizes image if it is needed!target = cv2.resize(src=target, dsize=size, interpolation=cv2.INTER_AREA)return targetdef show_image(img_arr):    plt.figure(figsize=(10,10))plt.axis("off")plt.imshow(img_arr/255)
plt.show()polygons = 128 #@param {type:"slider", min:10, max:1000, step:1}
size = 40 #@param {type:"slider", min:25, max:1000, step:5}
target_image = "Mona Lisa" #@param ["Mona Lisa", "Stop Sign", "Landscape", "Celebrity", "Art", "Abstract"]POLYGONS = polygons
SIZE = (size, size)target_urls = { "Mona Lisa" : 'https://upload.wikimedia.org/wikipedia/commons/b/b7/Mona_Lisa_face_800x800px.jpg',"Stop Sign" : 'https://images.uline.com/is/image//content/dam/images/H/H2500/H-2381.jpg',"Landscape" : 'https://www.adorama.com/alc/wp-content/uploads/2018/11/landscape-photography-tips-yosemite-valley-feature.jpg',"Celebrity" : 'https://s.abcnews.com/images/Entertainment/WireAP_91d6741d1954459f9993bd7a2f62b6bb_16x9_992.jpg',"Art" : "http://www.indianruminations.com/wp-content/uploads/what-is-modern-art-definition-2.jpg","Abstract" : "https://scx2.b-cdn.net/gfx/news/2020/abstractart.jpg"}target_image_url = target_urls[target_image]
target = load_target_image(target_image_url, size=SIZE)
show_image(target)
print(target.shape)

(2) 编写函数 extract_genes(),接受属性(基因)序列,并按照基因的长度进行拆分。本节中我们基于多边形作为绘图笔刷,但是也可以使用其他形状的笔刷(如圆形或矩形):

GENE_LENGTH = 10
NUM_GENES = POLYGONS * GENE_LENGTH#create a sample invidiual
individual = np.random.uniform(0,1,NUM_GENES)
print(individual)
# [0.15593761 0.42941275 0.69346004 ... 0.77075339 0.99245891 0.80209134]def extract_genes(genes, length): for i in range(0, len(genes), length): yield genes[i:i + length]

(3) 编写函数,用于绘制每个基因。首先构建绘图画布并提取基因:

def render_individual(individual):if isinstance(individual,list):individual = np.array(individual)canvas = np.zeros(SIZE+(3,))radius_avg = (SIZE[0] + SIZE[1]) / 2 / 6genes = extract_genes(individual, GENE_LENGTH)for gene in genes:

提取相关基因属性来定义每个画笔,其中前六个值表示绘制多边形的三个点或坐标,使用 cv2.fillPoly() 函数进行绘制。然后,提取的 alpha 值用于使用 cv2.addWeighted() 函数将画笔(叠加)覆盖在画布上。最后,绘制完所有基因定义的画笔后,返回最终的画布进行评估:

            x1 = int(gene[0] * SIZE[0])x2 = int(gene[2] * SIZE[0])x3 = int(gene[4] * SIZE[0])y1 = int(gene[1] * SIZE[1])y2 = int(gene[3] * SIZE[1])y3 = int(gene[5] * SIZE[1])color = (gene[6:-1] * 255).astype(int).tolist() pts = np.array([[x1,y1],[x2,y2],[x3,y3]], np.int32)  pts = pts.reshape((-1, 1, 2))pts = np.array([[x1,y1],[x2,y2],[x3,y3]])cv2.fillPoly(overlay, [pts], color)alpha = gene[-1]canvas = cv2.addWeighted(overlay, alpha, canvas, 1 - alpha, 0)  except:passreturn canvas

(4) 使用 render_individual() 函数渲染随机个体的结果如下所示:

render = render_individual(individual)
show_image(render)

随机渲染结果

在本节中,使用经典的蒙娜丽莎 (Mona Lisa) 图像,但我们也可以加载其他图像,观察代码运行结果。

(5) 我们可以逐像素点比较,使用均方误差 (mean-squared error, MSE) 评估个体的适应度,计算计算使用多边形画笔绘制的图像和原始图像之间的 MSE,然后将此误差作为个体的适应度分数返回,我们的目标是最小化此误差值:

from skimage.metrics import structural_similarity as ss
#@title Fitness Function
def fitness_mse(render):"""Calculates Mean Square Error Fitness for a render"""error = (np.square(render - target)).mean(axis=None)return errordef fitness_ss(render):"""Calculated Structural Similiarity Fitness"""index = ss(render, target, multichannel=True)return 1-indexprint(fitness_mse(render))
# 10661.935130594466

(6) 最后,定义遗传算子。定义函数 uniform(),用于从由下限和上限定义的均匀分布中生成浮点值,该函数注册了一个 attr_float 运算符,并用于 creator.Individual 运算符的注册中;最后,将 evaluate 函数注册为 evaluate 运算符:

creator.create("FitnessMax", base.Fitness, weights=(-1.0,))
creator.create("Individual", list, fitness=creator.FitnessMax)def uniform(low, up, size=None):try:return [random.uniform(a, b) for a, b in zip(low, up)]except TypeError:return [random.uniform(a, b) for a, b in zip([low] * size, [up] * size)]toolbox = base.Toolbox()
toolbox.register("attr_float", uniform, 0, 1, NUM_GENES)
toolbox.register("individual", tools.initIterate, creator.Individual, toolbox.attr_float)
toolbox.register("population", tools.initRepeat, list, toolbox.individual)def evaluate(individual):render = render_individual(individual)print('.', end='')
return fitness_mse(render),  #using MSE for fitnessdef register_selection(choice):choices = ["Tournament", "Roulette", "Random", "Best", "Worst", "NSGA2", "SPEA2"]if choice == choices[0]:toolbox.register("select", tools.selTournament, tournsize=3)elif choice == choices[1]:toolbox.register("select", tools.selRoulette)elif choice == choices[2]:toolbox.register("select", tools.selRandom)elif choice == choices[3]:toolbox.register("select", tools.selBest)elif choice == choices[4]:toolbox.register("select", tools.selWorst)elif choice == choices[5]:toolbox.register("select", tools.selNSGA2)elif choice == choices[6]:toolbox.register("select", tools.selSPEA2)def register_mating(choice):choices = ["Partially Matched", "One Point", "Two Point", "Ordered", "ES Two Point", "Uniform", "Uniform Partially Matched"]if choice == choices[0]:toolbox.register("mate", tools.cxPartialyMatched)elif choice == choices[1]:toolbox.register("mate", tools.cxOnePoint)elif choice == choices[2]:toolbox.register("mate", tools.cxTwoPoint)elif choice == choices[3]:toolbox.register("mate", tools.cxOrdered)elif choice == choices[4]:toolbox.register("mate", tools.cxESTwoPoint)elif choice == choices[5]:toolbox.register("mate", tools.cxUniform, indpb=.5)elif choice == choices[6]:toolbox.register("mate", tools.cxUniformPartialyMatched, indpb=.5)selection = "Tournament" #@param ["Tournament", "Random", "Best", "Worst", "NSGA2", "SPEA2"]
mating = "One Point" #@param ["Partially Matched", "One Point", "Two Point", "Ordered", "Uniform", "Uniform Partially Matched"]register_mating(mating)
register_selection(selection)toolbox.register("mutate", tools.mutGaussian, mu=0.0, sigma=1, indpb=.05)
toolbox.register("evaluate", evaluate)NGEN = 100000
CXPB = .6
MUTPB = .3
MU = 2500
pop = toolbox.population(n=MU)
hof = tools.HallOfFame(1)
stats = tools.Statistics(lambda ind: ind.fitness.values)
stats.register("avg", np.mean)
stats.register("std", np.std)
stats.register("min", np.min)
stats.register("max", np.max) best = Nonefor g in range(NGEN):pop, logbook = algorithms.eaSimple(pop, toolbox, cxpb=CXPB, mutpb=MUTPB, ngen=1, stats=stats, halloffame=hof, verbose=False)best = hof[0] clear_output()render = render_individual(best) show_image(render) print(f"Gen ({g}) : fitness = {fitness_mse(render)}")

下图展示了使用三角形笔刷运行约 5000 代的结果,我们也可以使用圆形或矩形笔刷进行绘制,并观察运行结果。

运行结果

修改超参数,并重新运行代码,尝试改进 EvoLisa 绘制图像的速度,或尝试调整 EvoLisa 使用的多边形(基因)数量。
EvoLisa 是十多年前展示遗传算法生成建模的示例。通过生成对抗网络 (Generative Adversarial Network, GAN) 或扩散模型等先进的生成模型能够得到远远优于 EvoLisa 的结果。然而,EvoLisa 展示了如何对基因或指令集进行编码和演化。虽然 DEAP 应用相似,但 EvoLisa 的底层机制展示了一种不同的优化形式。

小结

EvoLisa 是一个经典的遗传算法应用案例,展示了如何利用计算机算法来模仿艺术家的创作风格,尤其是在复杂的艺术形式中,如绘画和图像生成。本节中,我们使用 DEAP 通过复现 EvoLisa 项目重建《蒙娜丽莎》图像。

系列链接

遗传算法与深度学习实战(1)——进化深度学习
遗传算法与深度学习实战(2)——生命模拟及其应用
遗传算法与深度学习实战(3)——生命模拟与进化论
遗传算法与深度学习实战(4)——遗传算法详解与实现
遗传算法与深度学习实战(5)——遗传算法框架DEAP
遗传算法与深度学习实战(6)——DEAP框架初体验
遗传算法与深度学习实战(7)——使用遗传算法解决N皇后问题
遗传算法与深度学习实战(8)——使用遗传算法解决旅行商问题

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/414745.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【机器学习】集成学习------迅速了解什么是集成学习!!!

目录 🍔 为什么学习集成学习 🍔 什么是集成学习 🍔 集成学习分类的串行和并行学习算法 3.1 集成学习关键要素 3.2 集成学习器性能评估 🍔 小结 学习目标 🍀 知道什么是集成学习 🍀 知道集成学习的分类…

pandas操作Excel文件

pandas操作Excel文件 一、前言二、指定读取的工作表与header设置2.1指定工作表2.2header设置 三、读取Excel数据3.1iloc读取数据3.2read_excel读取数据3.3loc读取数据 四、DataFrame数据筛选4.1根据列标签对整列进行筛选4.2使用iloc对区域进行筛选4.3自定义筛选 五、DataFrame类…

对称密码学

1. 使用OpenSSL 命令行 在 Ubuntu Linux Distribution (发行版)中, OpenSSL 通常可用。当然,如果不可用的话,也可以使用下以下命令安装 OpenSSL: $ sudo apt-get install openssl 安装完后可以使用以下命令检查 OpenSSL 版本&am…

SQLi-LABS靶场56-60通过攻略

less-56 1.判断注入点 ?id1 页面不正常 2.判断闭合方式 ?id1) -- 可以闭合成功 3.查看页面回显点 ?id-1)%20 union select 1,2,3-- 4.查询数据库名 ?id-1)%20 union select 1,database(),3-- 5.查询所有表 ?id-1)%20 union select 1,(select table_name from inform…

Spring security的SecurityConfig配置时 userDetailsService报错如何解决?

文章目录 报错信息原因解决方案1. 实现 UserDetailsService 接口修改 IUsersService 接口和实现类 2. 修改 SecurityConfig3. 其他注意事项 报错信息 ‘userDetailsService(T)’ in ‘org.springframework.security.config.annotation.authentication.builders.AuthenticationM…

复习:虚析构函数(√)、纯虚析构函数(√)、虚构造函数(X)

虚析构函数 虚析构函数是为了解决基类的指针指向派生类对象&#xff0c;并用基类的指针删除派生类对 象。 #include <bits/stdc.h> #include <cstdio> #include <cstring> #include <iostream> using namespace std;class Base { public:Base(){cout…

银河麒麟v10-sp3 安装Tomcat10最新版

tomcat官方地址---Apache Tomcat - Apache Tomcat 10 Software Downloads 下载这个即可 Core&#xff1a; 含义&#xff1a;Core代表Tomcat的核心程序&#xff0c;即Tomcat的正式二进制发布版本。这是大多数用户做开发或学习时应该下载的版本。用途&#xff1a;包含了Tomcat服…

mysql的半同步模式

1.半同步模式原理 mysql的主备库通过binlog日志保持一致&#xff0c;主库本地执行完事务&#xff0c;binlog日志落盘后即返回给用户&#xff1b;备库通过拉取主库binlog日志来同步主库的操作。默认情况下&#xff0c;主库与备库并没有严格的同步&#xff0c;因此存在一定的概率…

Python 生成随机的国内 ip

示例代码&#xff1a; import randomdef generate_random_cn_ip():# 中国大陆IP范围start_ip "36.54.0.0"end_ip "123.255.255.254"# 将IP地址转换为整数start_ip_num int(start_ip.replace(".", ""))end_ip_num int(end_ip.rep…

Python日志重复?这里有终极解决方案!

文章目录 📖 介绍 📖🏡 演示环境 🏡📒 文章内容 📒📝 日志重复的常见原因📝 解决重复日志的策略📝 具体示例📝 日志重复问题的其他解决办法⚓️ 相关链接 ⚓️📖 介绍 📖 你是否曾经在调试Python程序时,发现同样的日志信息出现了两次甚至更多?这不仅…

前端框架vue3中的条件渲染(v-show,v-if,v-else-if,v-else)

目录 v-show: 需求&#xff1a; v-if 区别与v-show&#xff1a; v-if和v-show的选择&#xff1a; v-else-if和v-else 联合使用&#xff1a; v-show: 部分代码如图&#xff1a; <body><div id"root"><div ><h1>n的值为{{n}}</h1>…

新学期第一课

文章目录 一、加入课程QQ群&#xff08;一&#xff09;班级QQ群&#xff08;二&#xff09;入群要求 二、加入学习通班级群&#xff08;一&#xff09;学习通班级群&#xff08;二&#xff09;手势签到 三、使用思维导图工具&#xff08;一&#xff09;安装XMind&#xff08;二…

【QT | 开发环境搭建】Linux系统(Ubuntu 18.04) 安装 QT 5.12.12 开发环境

&#x1f601;博客主页&#x1f601;&#xff1a;&#x1f680;https://blog.csdn.net/wkd_007&#x1f680; &#x1f911;博客内容&#x1f911;&#xff1a;&#x1f36d;嵌入式开发、Linux、C语言、C、数据结构、音视频&#x1f36d; ⏰发布时间⏰&#xff1a; 2024-08-29 …

Kotaemon:开源的RAG UI

检索增强生成 (RAG) 已成为一种改变游戏规则的方法&#xff0c;可增强大型语言模型的功能。Kotaemon 是由 Cinnamon 开发的开源项目&#xff0c;它站在这项创新的最前沿&#xff0c;提供了一个简洁、可定制且功能丰富的基于 RAG 的用户界面&#xff0c;用于与文档聊天。 Kotae…

史记——我与历史的缘妙

究天人之际&#xff0c;通古今之变&#xff0c;成一家之言。 注解&#xff1a;这句话出自司马迁《史记》之《报任安书》。意思是通过“史实”现象揭示本质,探究自然现象和人类社会之间的相依相对关系。通晓从古到今的社会的各种发展演变,进而寻找历代王朝兴衰成败之道理。通过…

Mysql剖析(三)----MySql的事务详解

事务&#xff08;Transaction&#xff09;&#xff1a;一般是指要做的或所做的事情。在计算机术语中是指访问并可能更新数据库中的各种数据项的一个程序执行单元&#xff08;unit&#xff09;。事务通常由高级数据库操纵语言或编程语言(如SQL、C或Java)书写的用户程序的执行所引…

设施农业气象站

设施农业气象站的主要作用是为农业生产提供准确的气象数据和预测信息&#xff0c;以帮助农民科学决策和管理农业生产活动。具体作用包括&#xff1a; 提供准确的气象数据&#xff1a;设施农业气象站可以收集并记录气温、湿度、风速、降水量等多种气象信息&#xff0c;并确保数据…

探索存储世界:TF卡与SD卡的奥秘

在这个数字化时代&#xff0c;数据存储变得至关重要。TF卡&#xff08;TransFlash卡&#xff09;和SD卡&#xff08;Secure Digital卡&#xff09;作为两种常见的存储介质&#xff0c;它们在我们的日常生活中扮演着重要角色。MK米客方德将带您深入了解TF卡的基本概念&#xff0…

Python全网最全基础课程笔记-(一)基础入门

本专栏系列为Pythong基础系列&#xff0c;每天都会更新新的内容&#xff0c;搜罗全网资源以及自己在学习和工作过程中的一些总结&#xff0c;可以说是非常详细和全面。 以至于为什么要写的这么详细&#xff1a;自己也是学过Python的&#xff0c;很多新手只是简单的过一篇语法&a…

如何从 AWS CodeCommit 迁移到极狐GitLab?

极狐GitLab 是 GitLab 在中国的发行版&#xff0c;可以私有化部署&#xff0c;对中文的支持非常友好&#xff0c;是专为中国程序员和企业推出的企业级一体化 DevOps 平台&#xff0c;一键就能安装成功。安装详情可以查看官网指南。 本文将分享如何从 AWS CodeCommit 服务无缝迁…