Fast IFS using RPN notation
python
c
x86-64
nasm
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ifs5.py 4.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. import random
  2. import time
  3. import copy
  4. import numpy as np
  5. from skimage.restoration import estimate_sigma
  6. from .expr import *
  7. from .fractdim import *
  8. class IFS5(object):
  9. """ @brief 1 Variable IFS with R,G,B,A X,Y decomposition """
  10. #height=width=1024
  11. height=width=768
  12. #height=width=512
  13. def __init__(self, nexpr=4, init_sz=1, world=None):
  14. self._nexpr = nexpr
  15. self._expr = [[RpnExpr(sz=init_sz, nvar=6) for _ in range(6)]
  16. for _ in range(nexpr)]
  17. self._world = world
  18. if self._world is None:
  19. self._world = self.get_world()
  20. self._position = [random.randint(0, self.height-1),
  21. random.randint(0, self.width-1)]
  22. self._col = [random.randint(0, 255) for _ in range(4)]
  23. @classmethod
  24. def get_world(cls):
  25. return np.zeros((cls.height,cls.width,4), dtype=np.uint8)
  26. def raz_world(self):
  27. for i in range(self.height):
  28. for j in range(self.width):
  29. self._world[i][j] = [0,0,0,0]
  30. def __str__(self):
  31. el_lbl = 'XYrgba'
  32. fel = lambda el: ';'.join(['%s=(%s)' % (el_lbl[i], str(el[i]))
  33. for i in range(len(el))])
  34. ret = ';'.join(['<%s>' % fel(el) for el in self._expr])
  35. return ret
  36. def __copy__(self):
  37. ret = IFS5(nexpr=self._nexpr, world=self._world)
  38. ret._expr = [[copy.copy(e) for e in el]
  39. for el in self._expr]
  40. #ret._world = copy.deepcopy(self._world)
  41. return ret
  42. def get_image(self):
  43. return self._world
  44. def mutation(self, n=1, rand=True):
  45. n = 1 if n <= 1 else random.randint(1,n)
  46. for _ in range(n):
  47. random.choice(random.choice(self._expr)).mutation()
  48. def step(self):
  49. dr,dg,db,da = [int(e)
  50. for e in self._world[self._position[0]][self._position[1]]]
  51. cx = int((self._position[0] / self.width) * ((1<<64)-1))
  52. cy = int((self._position[0] / self.height) * ((1<<64)-1))
  53. args = (cx,cy,dr,dg,db,da)
  54. rx,ry,r,g,b,a = (int(expr.eval(*args))
  55. for expr in random.choice(self._expr))
  56. rx = (rx * (self.width-1)) // ((1<<64)-1)
  57. ry = (ry * (self.height-1)) // ((1<<64)-1)
  58. self._position[0], self._position[1] = rx, ry
  59. r,g,b,a = (c%256 for c in (r,g,b,a))
  60. sa = a/255
  61. outa = (a + da*(1-sa))/255
  62. if outa == 0:
  63. ro,go,bo = 0,0,0
  64. else:
  65. ro, go, bo = [(c*(a/255)+dc*da*(1-sa))/outa
  66. for c, dc in ((r,dr), (g, dg), (b, db))]
  67. r,g,b,a = [int(e) for e in (ro,go,bo,outa*255)]
  68. self._world[self._position[0]][self._position[1]] = [r,g,b,a]
  69. def score(self):
  70. start = time.time()
  71. colcount = len(np.unique(np.reshape(self._world[:,:,:3], (-1,3)),
  72. axis=0))
  73. #sigma = estimate_sigma(self._world, multichannel=True, average_sigmas=True)
  74. sigmas = estimate_sigma(self._world[:,:,:3], multichannel=True,
  75. average_sigmas=False)
  76. scores = [fractal_dimension(self._world[:,:,i]*self._world[:,:,3]/255)
  77. for i in range(3)]
  78. #alpha score
  79. #scores += [fractal_dimension(self._world[:,:,3])]
  80. gray = rgb2gray(self._world)
  81. graysigma = estimate_sigma(gray)
  82. grayscore = fractal_dimension(gray)
  83. del(gray)
  84. sigmas += [graysigma]*3
  85. sigmas = [0 if np.isnan(sigma) else sigma for sigma in sigmas]
  86. scores += [grayscore]*3
  87. sigma = sum(sigmas)/len(sigmas)
  88. mod = abs(scores[0]-scores[1])
  89. mod += abs(scores[0]-scores[2])
  90. mod += abs(scores[0]-scores[3])
  91. mod += abs(scores[1]-scores[2])
  92. mod += abs(scores[1]-scores[3])
  93. mod /= 5
  94. null_comp = 0
  95. for i in range(3):
  96. null_comp += 1 if scores[i] == 0 else 0
  97. if null_comp >= 2:
  98. score = 0
  99. mod *= 0.8
  100. else:
  101. score = sum(scores)/len(scores)
  102. score += mod
  103. if sigma and sigma > 0:
  104. score -= sigma/100
  105. #colscore = abs(colcount-1024) / 1e5
  106. colscore = abs(colcount-2048) / 1e5
  107. score -= colscore
  108. printscore = lambda arr: '['+(', '.join(['%1.3f' % e for e in arr]))+']'
  109. print("colscore %3.3f (%4d colors) scores time %5.2fs" % (colscore,
  110. colcount,
  111. time.time() - start))
  112. print("SIGMAS : %s SIGMA : %f " % (printscore(sigmas), sigma))
  113. print("SCORES : %s SCORE : %r" % (printscore(scores), score))
  114. return score