Advertisement
here2share

# random_art_256x256

Jun 12th, 2019
507
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 10.97 KB | None | 0 0
  1. #!/usr/bin/python
  2.  
  3. # Copyright (c) 2010, Andrej Bauer, http://andrej.com/
  4. # All rights reserved.
  5. #
  6. # Redistribution and use in source and binary forms, with or without
  7. # modification, are permitted provided that the following conditions are met:
  8. #
  9. #     * Redistributions of source code must retain the above copyright notice,
  10. #       this list of conditions and the following disclaimer.
  11. #
  12. #     * Redistributions in binary form must reproduce the above copyright
  13. #       notice, this list of conditions and the following disclaimer in the
  14. #       documentation and/or other materials provided with the distribution.
  15. #
  16. # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  17. # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  18. # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  19. # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
  20. # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  21. # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  22. # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  23. # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  24. # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  25. # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26.  
  27. ######################################################################
  28. # SIMPLE RANDOM ART IN PYTHON
  29. #
  30. # Version 2010-04-21
  31. #
  32. # I get asked every so often to release the source code for my random art
  33. # project at http://www.random-art.org/. The original source is written in Ocaml
  34. # and is not publicly available, but here is a simple example of how you can get
  35. # random art going in python in 250 lines of code.
  36. #
  37. # The idea is to generate expression trees that describe an image. For each
  38. # point (x,y) of the image we evaluate the expression and get a color. A color
  39. # is represented as a triple (r,g,b) where the red, green, blue components are
  40. # numbers between -1 and 1. In computer graphics it is more usual to use the
  41. # range [0,1], but since many operations are symmetric with respect to the
  42. # origin it is more convenient to use the interval [-1,1].
  43. #
  44. # I kept the program as simple as possible, and independent of any non-standard
  45. # Python libraries. Consequently, a number of improvements and further
  46. # experiments are possible:
  47. #
  48. #   * The most pressing problem right now is that the image is displayed as a
  49. #     large number of rectangles of size 1x1 on the tkinter Canvas, which
  50. #     consumes a great deal of memory. You will not be able to draw large images
  51. #     this way. An improved version would use the Python imagining library (PIL)
  52. #     instead.
  53. #
  54. #   * The program uses a simple RGB (Red Green Blue) color model. We could also
  55. #     use the HSV model (Hue Saturation Value), and others. One possibility is
  56. #     to generate a palette of colors and use only colors that are combinations
  57. #     of those from the palette.
  58. #
  59. #   * Of course, you can experiment by introducing new operators. If you are going
  60. #     to play with the source, your first exercise should be a new operator.
  61. #
  62. #   * The program uses cartesian coordinates. You could experiment with polar
  63. #     coordinates.
  64. #
  65. # For more information and further discussion, see http://math.andrej.com/category/random-art/
  66.  
  67. import math
  68. import random
  69. from Tkinter import * # Change "Tkinter" to "tkinter" in Python 3
  70.  
  71. # Utility functions
  72.  
  73. def average(c1, c2, w=0.5):
  74.     '''Compute the weighted average of two colors. With w = 0.5 we get the average.'''
  75.     (r1,g1,b1) = c1
  76.     (r2,g2,b2) = c2
  77.     r3 = w * r1 + (1 - w) * r2
  78.     g3 = w * g1 + (1 - w) * g2
  79.     b3 = w * b1 + (1 - w) * b2
  80.     return (r3, g3, b3)
  81.  
  82. def rgb(r,g,b):
  83.     '''Convert a color represented by (r,g,b) to a string understood by tkinter.'''
  84.     u = max(0, min(255, int(128 * (r + 1))))
  85.     v = max(0, min(255, int(128 * (g + 1))))
  86.     w = max(0, min(255, int(128 * (b + 1))))
  87.     return '#%02x%02x%02x' % (u, v, w)
  88.  
  89. def well(x):
  90.     '''A function which looks a bit like a well.'''
  91.     return 1 - 2 / (1 + x*x) ** 8
  92.  
  93. def tent(x):
  94.     '''A function that looks a bit like a tent.'''
  95.     return 1 - 2 * abs(x)
  96.  
  97. # We next define classes that represent expression trees.
  98.  
  99. # Each object that reprents and expression should have an eval(self,x,y) method
  100. # which computes the value of the expression at (x,y). The __init__ should
  101. # accept the objects representing its subexpressions. The class definition
  102. # should contain the arity attribute which tells how many subexpressions should
  103. # be passed to the __init__ constructor.
  104.  
  105. class VariableX():
  106.     arity = 0
  107.     def __init__(self): pass
  108.     def __repr__(self): return "x"
  109.  
  110.     def eval(self,x,y): return (x,x,x)
  111.  
  112. class VariableY():
  113.     arity = 0
  114.     def __init__(self): pass
  115.     def __repr__(self): return "y"
  116.     def eval(self,x,y): return (y,y,y)
  117.  
  118. class Constant():
  119.     arity = 0
  120.     def __init__(self):
  121.         self.c = (random.uniform(0,1), random.uniform(0,1), random.uniform(0,1))
  122.     def __repr__(self):
  123.         return 'Constant(%g,%g,%g)' % self.c
  124.     def eval(self,x,y): return self.c
  125.  
  126. class Sum():
  127.     arity = 2
  128.     def __init__(self, e1, e2):
  129.         self.e1 = e1
  130.         self.e2 = e2
  131.     def __repr__(self):
  132.         return 'Sum(%s, %s)' % (self.e1, self.e2)
  133.     def eval(self,x,y):
  134.         return average(self.e1.eval(x,y), self.e2.eval(x,y))
  135.  
  136. class Product():
  137.     arity = 2
  138.     def __init__(self, e1, e2):
  139.         self.e1 = e1
  140.         self.e2 = e2
  141.     def __repr__(self):
  142.         return 'Product(%s, %s)' % (self.e1, self.e2)
  143.     def eval(self,x,y):
  144.         (r1,g1,b1) = self.e1.eval(x,y)
  145.         (r2,g2,b2) = self.e2.eval(x,y)
  146.         r3 = r1 * r2
  147.         g3 = g1 * g2
  148.         b3 = b1 * b2
  149.         return (r3, g3, b3)
  150.  
  151. class Mod():
  152.     arity = 2
  153.     def __init__(self, e1, e2):
  154.         self.e1 = e1
  155.         self.e2 = e2
  156.     def __repr__(self):
  157.         return 'Mod(%s, %s)' % (self.e1, self.e2)
  158.     def eval(self,x,y):
  159.         (r1,g1,b1) = self.e1.eval(x,y)
  160.         (r2,g2,b2) = self.e2.eval(x,y)
  161.         try:
  162.             r3 = r1 % r2
  163.             g3 = g1 % g2
  164.             b3 = b1 % b2
  165.             return (r3, g3, b3)
  166.         except:
  167.             return (0,0,0)
  168.  
  169. class Well():
  170.     arity = 1
  171.     def __init__(self, e):
  172.         self.e = e
  173.     def __repr__(self):
  174.         return 'Well(%s)' % self.e
  175.     def eval(self,x,y):
  176.         (r,g,b) = self.e.eval(x,y)
  177.         return (well(r), well(g), well(b))
  178.  
  179. class Tent():
  180.     arity = 1
  181.     def __init__(self, e):
  182.         self.e = e
  183.     def __repr__(self):
  184.         return 'Tent(%s)' % self.e
  185.     def eval(self,x,y):
  186.         (r,g,b) = self.e.eval(x,y)
  187.         return (tent(r), tent(g), tent(b))
  188.  
  189. class Sin():
  190.     arity = 1
  191.     def __init__(self, e):
  192.         self.e = e
  193.         self.phase = random.uniform(0, math.pi)
  194.         self.freq = random.uniform(1.0, 6.0)
  195.     def __repr__(self):
  196.         return 'Sin(%g + %g * %s)' % (self.phase, self.freq, self.e)
  197.     def eval(self,x,y):
  198.         (r1,g1,b1) = self.e.eval(x,y)
  199.         r2 = math.sin(self.phase + self.freq * r1)
  200.         g2 = math.sin(self.phase + self.freq * g1)
  201.         b2 = math.sin(self.phase + self.freq * b1)
  202.         return (r2,g2,b2)
  203.  
  204. class Level():
  205.     arity = 3
  206.     def __init__(self, level, e1, e2):
  207.         self.treshold = random.uniform(-1.0,1.0)
  208.         self.level = level
  209.         self.e1 = e1
  210.         self.e2 = e2
  211.     def __repr__(self):
  212.         return 'Level(%g, %s, %s, %s)' % (self.treshold, self.level, self.e1, self.e2)
  213.     def eval(self,x,y):
  214.         (r1, g1, b1) = self.level.eval(x,y)
  215.         (r2, g2, b2) = self.e1.eval(x,y)
  216.         (r3, g3, b3) = self.e2.eval(x,y)
  217.         r4 = r2 if r1 < self.treshold else r3
  218.         g4 = g2 if g1 < self.treshold else g3
  219.         b4 = b2 if b1 < self.treshold else b3
  220.         return (r4,g4,b4)
  221.  
  222. class Mix():
  223.     arity = 3
  224.     def __init__(self, w, e1, e2):
  225.         self.w = w
  226.         self.e1 = e1
  227.         self.e2 = e2
  228.     def __repr__(self):
  229.         return 'Mix(%s, %s, %s)' % (self.w, self.e1, self.e2)
  230.     def eval(self,x,y):
  231.         w = 0.5 * (self.w.eval(x,y)[0] + 1.0)
  232.         c1 = self.e1.eval(x,y)
  233.         c2 = self.e2.eval(x,y)
  234.         return average(c1,c2,)
  235.  
  236. # The following list of all classes that are used for generation of expressions is
  237. # used by the generate function below.
  238.  
  239. operators = (VariableX, VariableY, Constant, Sum, Product, Mod, Sin, Tent, Well, Level, Mix)
  240.  
  241. # We precompute those operators that have arity 0 and arity > 0
  242.  
  243. operators0 = [op for op in operators if op.arity == 0]
  244. operators1 = [op for op in operators if op.arity > 0]
  245.  
  246. def generate(k = 50):
  247.     '''Randonly generate an expession of a given size.'''
  248.     if k <= 0:
  249.         # We used up available size, generate a leaf of the expression tree
  250.         op = random.choice(operators0)
  251.         return op()
  252.     else:
  253.         # randomly pick an operator whose arity > 0
  254.         op = random.choice(operators1)
  255.         # generate subexpressions
  256.         i = 0 # the amount of available size used up so far
  257.         args = [] # the list of generated subexpression
  258.         for j in sorted([random.randrange(k) for l in range(op.arity-1)]):
  259.             args.append(generate(j - i))
  260.             i = j
  261.         args.append(generate(k - 1 - i))
  262.         return op(*args)
  263.  
  264. class Art():
  265.     """A simple graphical user interface for random art. It displays the image,
  266.       and the 'Again!' button."""
  267.  
  268.     def __init__(self, master, size=256):
  269.         master.title('Random art')
  270.         self.size=size
  271.         self.canvas = Canvas(master, width=size, height=size)
  272.         self.canvas.grid(row=0,column=0)
  273.         b = Button(master, text='Again!', command=self.redraw)
  274.         b.grid(row=1,column=0)
  275.         self.draw_alarm = None
  276.         self.redraw()
  277.  
  278.     def redraw(self):
  279.         if self.draw_alarm: self.canvas.after_cancel(self.draw_alarm)
  280.         self.canvas.delete(ALL)
  281.         self.art = generate(random.randrange(20,150))
  282.         self.d = 64   # current square size
  283.         self.y = 0    # current row
  284.         self.draw()
  285.  
  286.     def draw(self):
  287.         if self.y >= self.size:
  288.             self.y = 0
  289.             self.d = self.d // 4
  290.         if self.d >= 1:
  291.             for x in range(0, self.size, self.d):
  292.                     u = 2 * float(x + self.d/2)/self.size - 1.0
  293.                     v = 2 * float(self.y + self.d/2)/self.size - 1.0
  294.                     (r,g,b) = self.art.eval(u, v)
  295.                     self.canvas.create_rectangle(x,
  296.                                                  self.y,
  297.                                                  x+self.d,
  298.                                                  self.y+self.d,
  299.                                                  width=0, fill=rgb(r,g,b))
  300.             self.y += self.d
  301.             self.draw_alarm = self.canvas.after(1, self.draw)
  302.         else:
  303.             self.draw_alarm = None
  304.  
  305. # Main program
  306. win = Tk()
  307. arg = Art(win)
  308. win.mainloop()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement