溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

python如何實現(xiàn)使用遺傳算法進行圖片擬合

發(fā)布時間:2022-03-11 14:07:58 來源:億速云 閱讀:170 作者:小新 欄目:開發(fā)技術(shù)

小編給大家分享一下python如何實現(xiàn)使用遺傳算法進行圖片擬合,希望大家閱讀完這篇文章之后都有所收獲,下面讓我們一起去探討吧!

引言

算法思路

假設(shè)我們有這樣一個生物族群,他們的每個基因片段都是一個個三角形(即只含三個點和顏色信息),他們每個個體表現(xiàn)出的性狀就是若干個三角形疊加在一起。假設(shè)我們有一張圖片可以作為這種生物族群最適應(yīng)環(huán)境的性狀,即長得越像這張圖片的越能適應(yīng)環(huán)境,越不像這張圖片的越容易被淘汰。

當然作為一個正常的生物族群,他應(yīng)該也會有正常的繁衍以產(chǎn)生新個體。產(chǎn)生新個體的過程中來自父親和母親的基因會進行交叉互換和變異,變異又可以有增加基因片段、減少基因片段以及不同位置的基因片段順序互換。

但是一個族群不能夠無限的繁殖,我們假設(shè)環(huán)境資源只能容納有限的生物族群規(guī)模,所以我們在產(chǎn)生足夠多的后代之后就要把他們放到族群里與族群內(nèi)部進行競爭淘汰。這樣一來,通過不斷地淘汰,這個族群就會越來越像我們給定的圖片。這就是算法的基本思路。

流程圖

python如何實現(xiàn)使用遺傳算法進行圖片擬合

下面我們來看一下實現(xiàn)過程,為了方便解釋,我們會結(jié)合python建立類似于偽代碼的函數(shù)進行解釋,不能直接運行,具體可運行的代碼可直接下載參照最后的類封裝的完整代碼

預(yù)備知識及準備工作

打開圖片

我們使用imageio中的imread打開圖片,這里為了方便后續(xù)使用我們建立OpenImg函數(shù),返回打開的圖片img(格式為array),圖片的格式(方便后期圖片的保存),圖片的大?。簉ow和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

隨機生成生物族群

我們假設(shè)一個族群的最大生物個數(shù)為max_group,用groups來表示族群,g為族群內(nèi)的生物個體,運用隨機數(shù)隨機產(chǎn)生個體。

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

對比生物個體和目標圖片的相似度

使用structural_similarity對比兩個圖片的相似度,此時兩個圖片都應(yīng)該是array類型

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

保存圖片

調(diào)用我們之前建立好的to_image函數(shù)先將個體轉(zhuǎn)換成圖片,然后將圖片保存即可。

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

算法主體

交叉互換

考慮到后期的基因片段的增添和減少,所以應(yīng)該分為兩步,其一是相重合的位置進行交叉互換,以及對于多出來的尾部進行交叉互換,我們按照隨機率random_rate和重合位置長度min_locate來確定交換的位數(shù)。然后我們使用sample選出若干位置進行互換。交換結(jié)束后再對尾部進行互換

random_rate = random()

def exchange(father, mother)->[]:
	# 交換
	# 隨機生成互換個數(shù)
	min_locate = min(len(father), len(mother))
	n = randint(0, int(random_rate * min_locate))
	# 隨機選出多個位置
	selected = sample(range(0, min_locate), n)
	# 交換內(nèi)部
	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):
	# 突變
	# 隨機生成變異個數(shù)
	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

基因片段易位

在個體的基因組內(nèi)隨機選擇基因片段進行位置互換。

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

增加基因片段

直接在個體基因組后面添加隨機產(chǎn)生的基因片段即可。

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

變異

以此調(diào)用以上的突變、易位、增添和減少產(chǎn)生4種狀態(tài)的基因片段

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

繁殖

繁殖過程包括交叉互換和變異,直接調(diào)用之前構(gòu)造的函數(shù)即可

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]

淘汰

建立個體和其與目標的相似度相關(guān)的映射關(guān)系,并按照相似度排序,然后去除相似度較低的個體,直到剩余生物個體的數(shù)量為max_group為止。在這個函數(shù)中我們還返回了一個最優(yōu)個體的相似度來方便監(jiān)測。

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]

擬合

擬合過程先要進行若干次的繁殖,為了保證每次繁殖的個體數(shù)我們規(guī)定其至少選擇最大個體數(shù)的一半數(shù)量的次數(shù)進行繁殖,繁殖之后的個體加入到種群當作和之前種群中的個體一起進行淘汰。通過這個過程我們每次淘汰都會將與目標差距最大的個體淘汰。

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)

原圖

我們以擬合一個小藍鳥和一個心形為例來展示擬合過程

python如何實現(xiàn)使用遺傳算法進行圖片擬合
python如何實現(xiàn)使用遺傳算法進行圖片擬合

擬合過程展示

代碼實現(xiàn)(這里已經(jīng)事先將重復(fù)圖片刪除了)

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()

效果

python如何實現(xiàn)使用遺傳算法進行圖片擬合

python如何實現(xiàn)使用遺傳算法進行圖片擬合

看完了這篇文章,相信你對“python如何實現(xiàn)使用遺傳算法進行圖片擬合”有了一定的了解,如果想了解更多相關(guān)知識,歡迎關(guān)注億速云行業(yè)資訊頻道,感謝各位的閱讀!

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI