Аппроксимация Изображений Случайными Линиями

Я экспериментировал с итеративным генерированием приближений изображения с использованием черных линий.

Алгоритм работает путем случайного размещения 40 черных линий на 40 копиях пустого исходного изображения, каждый из этих 40 затем сравнивается с целевым изображением с помощью SSIM для измерения сходства. Если какой-либо из 40 более похож, чем исходное изображение, это изображение используется в качестве источника для следующей итерации алгоритма. Если ни один из 40 не более похож, то алгоритм повторяется с исходным исходным изображением до тех пор, пока не будет найдено более близкое сходство.

SSIM был выбран в качестве измерителя сходства как лучший. По сравнению с традиционными методами PSNR или метода среднеквадратичной ошибки, потому что он более подходящий (хотя и не идеальный) метод измерения сходства между двумя изображениями, воспринимаемыми человеческим глазом.

Построение изменения в SSIM за 9000 циклов приводит к следующему довольно предсказуемому графику.

Из этого графика видно, что за пределами примерно 3500 итераций получается небольшое дополнительное структурное сходство.

Исходный код

Код для этого проекта был написан на python, основанном в основном на библиотеках PIL и pyssim. Ниже приведена версия кода, используемого для создания вышеуказанных изображений.

Число итераций жестко закодировано до 9000, а число изображений в генерации установлено на 40. Это довольно произвольные решения и они могут быть легко изменены в коде для экспериментов. Также в код включены два метода вычисления psnr и метод среднеквадратичной ошибки.

#!/usr/bin/env python

from PIL import Image
from PIL import ImageDraw
from random import randint
import ssim
import os
import math
import numpy as np

def generate_line(max_width, max_height, max_length=50):
	start = (randint(0,max_width),randint(0,max_width))
	length = float(randint(0, max_length))
	angle = math.radians(float(randint(0,360)))
	x = length * math.cos(angle) + start[0]
	y = length * math.sin(angle) + start[1]
	line = [start,(x,y)]
	return line


def mean_squared_error(img1, img2):
    total =0
    size = img1.size
    if img1.size != img2.size:
        raise Exception("size of images must be the same")
    if img1.mode != 'L':
        img1 = img1.convert('L')
    if img2.mode != 'L':
        img2 = img2.convert('L')

    img1 = np.array(img1.getdata())
    img2 = np.array(img2.getdata())
    
    return np.mean(np.absolute(img1 -img2))/255.0

def psnr(img1,img2):
    mse = mean_squared_error(img1,img2)
    return 10.0*math.log10(1.0/mse)

def main():
	img = Image.open("kitten.png")
	result_img = Image.new("RGB",img.size)

	draw = ImageDraw.Draw(result_img)
	draw.rectangle([(0,0),result_img.size],fill=(255,255,255))
	max_width, max_height = result_img.size

	for i in range(9000):
		best_img = result_img.copy()
		best_score = ssim.compute_ssim(img,result_img)

		for l in range(40):
			temp_img = result_img.copy()
			draw = ImageDraw.Draw(temp_img)
			line = generate_line(max_width, max_height)
			draw.line(line,width=1, fill=(0,0,0))
			score = ssim.compute_ssim(img,temp_img)
			print score
			if score > best_score:
				score = best_score
				best_img = temp_img.copy()
		
		result_img = best_img
		output_name = str(i).zfill(6)+'.png'
		result_img.save(output_name)

	result_img.show()
	img.show()

if __name__ == "__main__":
	main()

Установка в Ubuntu

Pyssim может быть установлен через pip (индекс пакета python). Чтобы запустить pip:

sudo apt-get install python-pip

Чтобы ускорить процесс, я рекомендую установить следующие пакеты перед установкой pyssim:

sudo apt-get install python-matplotlib python-scipy python-numpy

В завершение, выполните следующую команду для установки pyssim через pip:

sudo pip install pyssim