rpnifs/python_rpnifs/ifs2.py

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