89 lines
2.8 KiB
Python
89 lines
2.8 KiB
Python
import random
|
|
import copy
|
|
|
|
import numpy as np
|
|
from skimage.restoration import estimate_sigma
|
|
|
|
from .expr import *
|
|
from .fractdim import *
|
|
|
|
alpha=32
|
|
calpha = lambda n, c=255, a=10: -int(((c*a/255)-c)*(1-(1-a/255)**n))
|
|
calphas = [[calpha(i, c, alpha) for i in range(0x1000)]
|
|
for c in range(256)]
|
|
|
|
class IFS2(object):
|
|
""" @brief 1 Variable IFS with X,Y decomposition """
|
|
|
|
|
|
#height=width=1024
|
|
height=width=512
|
|
|
|
def __init__(self, nexpr=4, init_sz=1, world=None, alpha=16):
|
|
self._alpha = alpha
|
|
self._nexpr = nexpr
|
|
self._expr = [RpnExpr(sz=init_sz, nvar=1)
|
|
for _ in range(nexpr)]
|
|
self._world = world
|
|
if self._world is None:
|
|
self._world = self.get_world()
|
|
#self._position = [random.randint(0, self.height-1),
|
|
# random.randint(0, self.width-1)]
|
|
self._position = [self.height//2, self.width//2]
|
|
|
|
@classmethod
|
|
def get_world(cls):
|
|
return np.zeros((cls.height,cls.width), dtype=np.uint32)
|
|
|
|
def raz_world(self):
|
|
for i in range(self.height):
|
|
for j in range(self.width):
|
|
self._world[i][j] = 0
|
|
|
|
def __str__(self):
|
|
return ";".join([str(e) for e in self._expr])
|
|
|
|
def __copy__(self):
|
|
ret = IFS2(nexpr=self._nexpr, world=self._world)
|
|
ret._expr = [copy.copy(e) for e in self._expr]
|
|
#ret._world = copy.deepcopy(self._world)
|
|
return ret
|
|
|
|
def mutation(self, n=1, rand=True):
|
|
n = 1 if n <= 1 else random.randint(1,n)
|
|
for _ in range(n):
|
|
random.choice(self._expr).mutation()
|
|
|
|
def step(self):
|
|
arg = self._position[0]
|
|
arg <<=32
|
|
arg += self._position[1]
|
|
|
|
ret = int(random.choice(self._expr).eval(arg))
|
|
|
|
self._position[1] = (ret & 0xFFFFFFFF)%self.width
|
|
ret >>= 32
|
|
self._position[0] = (ret & 0xFFFFFFFF)%self.height
|
|
|
|
self._world[self._position[0]][self._position[1]] += 1
|
|
|
|
def get_image(self, color=(0,0xFF,0x0)):
|
|
return np.array([[[calpha(n, c, self._alpha) if n and c else 0 for c in color]
|
|
for n in line]
|
|
for line in self._world], dtype=np.uint8)
|
|
|
|
|
|
def score(self):
|
|
#maxi = self._world.max()
|
|
#mini = self._world.min()
|
|
#gray = np.array((self._world - mini)/(maxi-mini)*255, dtype=np.uint8)
|
|
gray = np.array([[calpha(n, 255, self._alpha) if n else 0
|
|
for n in line]
|
|
for line in self._world], dtype=np.uint8)
|
|
sigma = estimate_sigma(gray, multichannel=False, average_sigmas=True)
|
|
sigma = 0 if np.isnan(sigma) else sigma
|
|
score = fractal_dimension(gray, 128)
|
|
|
|
if sigma and sigma > 5:
|
|
score /= sigma/5
|
|
return score
|