Python实现遗传算法图像拟合:从原理到完整代码

何川
何川
发布时间:2026-10-16| 5人浏览过
原创

本文详解如何使用Python实现基于遗传算法的图片拟合。通过将图像分解为三角形基因片段,利用交叉、变异和自然选择机制,逐步进化出与目标图像高度相似的结果。文章涵盖算法原理、核心代码实现及完整类封装,适合对进化计算和图像处理感兴趣的开发者。

引言

算法思路

设想一个生物群体,其每个个体的基因由若干三角形构成,每个三角形仅包含三个顶点坐标及颜色信息。个体的表型表现为这些三角形的叠加效果。若将一张目标图片视为该环境下的最优性状,则个体与目标图片越相似,其适应度越高,越容易被保留;反之,差异较大的个体则面临淘汰。

在自然繁衍过程中,子代个体的基因来自父母双方,并经历交叉互换与变异。变异操作包括增加或减少基因片段数量,以及调整不同位置基因片段的顺序,从而引入多样性。

由于环境资源有限,群体规模不能无限扩张。因此,在生成足够多的后代后,需将其与现有群体混合并进行竞争淘汰。通过持续的优胜劣汰,群体整体逐渐逼近目标图片的形状与颜色分布。这便是该遗传算法的核心逻辑。

流程图

接下来展示具体实现过程。为便于理解,文中使用Python编写类似伪代码的函数进行说明,这些代码不可直接运行。如需完整可执行代码,请参考文末封装好的类文件。

预备知识及准备工作

打开图片

使用imageio库的imread函数加载图片。为简化后续处理,定义OpenImg函数,返回处理后的图片数组(img)、文件扩展名(用于保存)以及图片的行数(row)和列数(col),后者用于绘图时的坐标计算。

from imageio import imread

def OpenImg(imgPath):
	img = imread(imgPath)
    row, col = img.shape[0], img.shape[1]
    return img, imgPath.split(".")[-1], row, col

随机生成生物族群

设定群体最大个体数max_group,用groups列表存储所有个体。每个个体g由若干随机生成的三角形基因片段组成,通过随机数生成初始种群。

from random import choice

for i in range(max_group):
	g = []
    for j in range(features):
	    tmp = [[choice(np.linspace(0, row, features)), choice(np.linspace(0, col, features))] for x in range(3)]
        tmp.append("#" + ''.join(choice('0123456789ABCDEF') for x in range(6)))

    g.append(tmp.copy())
    groups.append(g.copy())

按照生物性状画图

利用PIL库进行图像绘制。首先创建空白画布,随后将个体中的每个三角形(包括顶点坐标和颜色)绘制到画布上,生成该个体的视觉表现。

from PIL import Image, ImageDraw

def to_image(g):
	array = np.ndarray((img.shape[0], img.shape[1], img.shape[2]), np.uint8)
	array[:, :, 0] = 255
	array[:, :, 1] = 255
	array[:, :, 2] = 255
	newIm1 = Image.fromarray(array)
	draw = ImageDraw.Draw(newIm1)
	for d in g:
		draw.polygon((d[0][0], d[0][1], d[1][0], d[1][1], d[2][0], d[2][1]), d[3])

	return newIm1

对比生物个体和目标图片的相似度

使用skimage.metrics中的structural_similarity函数计算两个数组类型图片的结构相似度。该指标能更准确地反映图像间的视觉差异。

from skimage.metrics import structural_similarity

def getSimilar(g) -> float:
	newIm1 = to_image(g)
    ssim = structural_similarity(np.array(img), np.array(newIm1), multichannel=True)
    return ssim

保存图片

调用之前定义的to_image函数将个体基因转换为图像对象,然后使用save方法将图片保存至指定路径,便于观察进化过程。

def draw_image(g, cur, imgtype):
    image1 = to_image(g)
    image1.save(os.path.join(str(cur) + "." + imgtype))

算法主体

交叉互换

考虑到基因片段的动态增减,交叉操作分为两部分:重合区域的交换和尾部片段的交换。根据随机率random_rate和最小定位长度min_locate确定交换位数,使用sample函数选取若干位置进行互换。交换完成后,再对剩余尾部片段进行互换处理。

random_rate = random()

def exchange(father, mother)->[]:
	# 交换
	# 随机生成互换个数
	min_locate = min(len(father), len(mother))
	n = randint(0, int(random_rate * min_locate))
	# 随机选出多个位置
	selected = sample(range(0, min_locate), n)
	# 交换内部
	for s in selected:
		father[s], mother[s] = mother[s], father[s]

  	# 交换尾部
	locat = randint(0, min_locate)
	fhead = father[:locat].copy()
	mhead = mother[:locat].copy()

	ftail = father[locat:].copy()
	mtail = mother[locat:].copy()

	# print(fhead, ftail, mhead, mtail)
	fhead.extend(mtail)
	father = fhead
	mhead.extend(ftail)
	mother = mhead
	return [father, mother]

基因突变

突变机制与交叉类似,旨在增加多样性。具体操作是随机选择某些基因片段,并重新生成其顶点坐标和颜色信息,视为一次突变事件。

random_rate = random()

def mutation(gen):
	# 突变
	# 随机生成变异个数
	n = int(randint(1, 100) / 1000 * len(gen))
	selected = sample(range(0, len(gen)), n)

	for s in selected:
		tmp = [[choice(np.linspace(0, row, 100)), choice(np.linspace(0, col, 100))] for x in	range(3)]
		tmp.append("#" + ''.join(choice('0123456789ABCDEF') for x in range(6)))
		gen[s] = tmp

	return gen

基因片段易位

在个体基因组内部,随机选择两个基因片段并交换它们的位置,以此改变基因排列顺序,增加搜索空间的探索能力。

def move(gen):
	# 易位
	exchage = int(randint(1, 100) / 1000 * len(gen))
	for e in range(exchage):
		sec1 = randint(0, len(gen) - 1)
		sec2 = randint(0, len(gen) - 1)

		gen[sec1], gen[sec2] = gen[sec2], gen[sec1]
	
	return gen

增加基因片段

直接在个体基因组末尾添加随机生成的新三角形基因片段,以增加图像的复杂度与细节表现力。

features = 100
def add(gen):
	# 增加
	n = int(randint(1, 100) / 1000 * len(gen))
	for s in range(n):
		tmp = [[choice(np.linspace(0, row,features)),choice(np.linspace(0, col, features))] for x in range(3)]
		tmp.append("#" + ''.join(choice('0123456789ABCDEF') for x in range(6)))
		gen.append(tmp)
		
	return gen

减少基因片段

随机选择个体中的若干基因片段并将其移除,简化图像结构,防止过拟合或计算冗余。

def cut(self, gen):
    # 减少
	n = int(randint(1, 100) / 1000 * len(gen))
	selected = sample(range(0, len(gen)), n)

	g = []
	for gp in range(len(gen)):
		if gp not in selected:
			g.append(gen[gp])

    return g

变异

综合上述四种操作(突变、易位、增加、减少),生成多种变异状态的基因片段,为下一轮进化提供丰富的候选个体。

 def variation(gen):
	# 变异
	gen = mutation(gen.copy())
	gen1 = move(gen.copy())
	gen2 = add(gen1.copy())
	gen3 = cut(gen2.copy())
	return [gen, gen1, gen2, gen3]

繁殖

繁殖过程包括交叉互换和变异操作,直接调用之前定义的exchange和variation函数即可生成子代群体。

def breeds(father, mother):
	new1, new2 = exchange(father.copy(), mother.copy())
	# 变异
	new3, new4, new5, new6 = variation(father.copy())
	new7, new8, new9, new10 = variation(mother.copy())

	return [new1, new2, new3, new4, new5, new6, new7, new8, new9, new10]

淘汰

建立个体与其目标相似度之间的映射关系,按相似度从高到低排序。移除相似度较低的个体,直至剩余个体数量等于max_group。该函数同时返回最优个体的相似度值,用于监控进化进度。

def eliminated(groups):
	group_dict = dict()
	for gp in range(len(groups)):
		group_dict[gp] = getSimilar(groups[gp])

	group_dict = {key: value for key, value in sorted(group_dict.items(), key=lambda item: item[1], reverse=True)}
	g = []
	for key in list(group_dict.keys())[:max_group]:
		g.append(groups[key].copy())

	groups = g.copy()
	return groups, list(group_dict.values())[0]

拟合

拟合过程包含多次繁殖迭代。为保证每次繁殖的个体数量,规定至少进行最大个体数一半次数的繁殖操作。繁殖后的子代加入原种群,共同经历淘汰过程。通过这种机制,每一轮迭代都会剔除与目标差距最大的个体,逐步逼近最优解。

def breeds(father, mother):
	new1, new2 = exchange(father.copy(), mother.copy())
	# 变异
	new3, new4, new5, new6 = variation(father.copy())
	new7, new8, new9, new10 = variation(mother.copy())

	return [new1, new2, new3, new4, new5, new6, new7, new8, new9, new10]

示例展示

拟合时建议选择分辨率较低的图片。若使用高分辨率图片,可使用以下代码降低图片分辨率以加速计算。

降低图片分辨率

from imageio import imread
from PIL import Image

imgPath = input("输入图片路径")
img = imread(imgPath)
img = img[::2, ::2, :]
img = Image.fromarray(img)
img.save(imgPath)

原图

以拟合一个小蓝鸟图标和一个心形图案为例,展示整个进化过程。


拟合过程展示

代码实现(这里已经事先将重复图片删除了)

import os
import math
import matplotlib.pyplot as plt
import matplotlib.image as image

path = "./xl"
length = len(os.listdir(path))
row = col = math.ceil(math.sqrt(length))
x = 1


lst = []
for d in os.listdir(path):
    lst.append(int(d.split('.')[0]))
lst = sorted(lst)

for l in lst:
    img = image.imread(os.path.join(path, str(l)+'.png'))
    plt.xticks([])
    plt.yticks([])
    plt.subplot(row, col, x)
    plt.imshow(img)
    plt.xticks([])
    plt.yticks([])
    plt.title(str(l))
    x += 1


plt.savefig(path)
plt.show()

效果

完整代码下载(已封装成类)

GitHub下载地址(推荐): https://github.com/AiXing-w/Python-Intelligent-Optimization-Algorithms

到此这篇关于python实现使用遗传算法进行图片拟合的文章就介绍到这了,更多相关python 图片拟合内容请搜索本站以前的文章或继续浏览下面的相关文章希望大家以后多多支持本站!

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。