Saturday, December 28, 2013

Using Python to create Mondrian-like images

[]

Piet Mondrian is best known for his paintings of simple rectangular forms and lines. Since they appear fairly straightforward, I thought it would be possible to develop some code to make lookalike images.

I made some choices in the code below to make things a little easier. After first creating an empty, white image, positions for all horizontal and vertical lines are chosen, with the limit that they must be at least five pixels apart and five pixels from the edge. Next about half are chosen to be full-length lines. Then, the remaining lines are given endpoints either at the edge or on one of the full-length lines.

Once the lines are drawn, a loop chooses a random white point in the image and finds its dimensions, defining a rectangle. That rectangle is then filled with a random choice from the palette defined near the beginning.

Depending on the parameters chosen, the result can be Mondrian-like, or something very different.

In [2]:
from PIL import Image
import random

####################
#Parameters
####################
mond_size_x = 200
mond_size_y = 200
num_lines_x = 10
num_lines_y = 10
fields_wanted = 15
images_wanted = 1

#####################
#Some color definitions
#####################
blue = (0,0,255)
red = (255,0,0)
yellow = (255,255,0)
illini_blue_bold = (0,60,125)
illini_orange_bold = (244,127,36)
illini_blue_prof = (110,139,191)
illini_orange_prof = (239,138,28)
darkgreen = (0,100,0)
darkred = (139,0,0)
forestgreen = (34,139,34)
rand1 = (random.randrange(0,255), random.randrange(0,255), random.randrange(0,255))

###################
#Palette choice
###################
final_palette = [yellow, blue, red,]


##################
#Image production
##################
imagecounter = 1
while images_wanted >= imagecounter:

 ###Makes empty image
 Mond1 = Image.new("RGB",(mond_size_x,mond_size_y))
 Mond1_pixels = Mond1.load()
 for i in range(0,mond_size_x):
  for j in range(0,mond_size_y):
   Mond1_pixels[i,j] = (255,255,255)

 ###Pick line positions
 good = 0
 vind = []
 hind = []
 while good < 1:
  poss_index_x = range(4,mond_size_x-6)
  for j in range(num_lines_x):
   thisx = random.choice(poss_index_x)
   vind.append(thisx)
   for q in range(thisx - 5, thisx + 5):
    if q in poss_index_x:
     poss_index_x.remove(q)   
  
  poss_index_y = range(4,mond_size_y-6)
  for j in range(num_lines_y):
   thisy = random.choice(poss_index_y)
   poss_index_y.remove(thisy)
   hind.append(thisy)
   for q in range(thisy - 5, thisy + 5):
    if q in poss_index_y:
     poss_index_y.remove(q)   
  good = 1 

 shorth=[]
 shortv=[] 
 fullh = random.sample(hind,num_lines_y/2)
 fullv = random.sample(vind,num_lines_x/2)

 for j in fullh:
  for r in range(mond_size_x):
   Mond1_pixels[r,j] = (0,0,0)
 for j in fullv:
  for r in range(mond_size_y):
   Mond1_pixels[j,r] = (0,0,0)
   
 hends = [0,mond_size_y]
 vends = [0, mond_size_x]
 for j in fullv:
  vends.append(j)
 for j in fullh:
  hends.append(j)

 for j in vind:
  if j not in fullv:
   shortv.append(j)
 for j in hind:
  if j not in fullh:
   shorth.append(j)
  
 for k in shorth:
  ends = random.sample(vends,2)
  ends.sort()
  for p in range(ends[0] ,ends[1] ):
   Mond1_pixels[p,k] = (0,0,0)

 for k in shortv:
  ends = random.sample(hends,2)
  ends.sort()
  for p in range(ends[0],ends[1]):
   Mond1_pixels[k,p] = (0,0,0)  
   
 ###Fill the fields
 total_fields = 0
 while total_fields < fields_wanted:
  
  ###Pick random white pixel
  done = 0
  while done != 1:
   rand_row = random.randrange(0,mond_size_y)
   rand_col = random.randrange(0,mond_size_x)
   if Mond1_pixels[rand_col,rand_row] == (255,255,255):
    done = 1

  ###Grow down
  this_pixel_row = rand_row
  this_pixel_column = rand_col
  this_pixel_color = Mond1_pixels[this_pixel_column,this_pixel_row]
  while this_pixel_color == (255,255,255):
   if this_pixel_row < (mond_size_y - 1):
    this_pixel_row = this_pixel_row + 1
    this_pixel_color = Mond1_pixels[this_pixel_column,this_pixel_row]
   else:
    this_pixel_color = (0,0,0)
    this_pixel_row = this_pixel_row + 1
  bottom_white_row = this_pixel_row-1
  
  ###Grow up
  this_pixel_row = rand_row
  this_pixel_column = rand_col
  this_pixel_color = Mond1_pixels[this_pixel_column,this_pixel_row]
  while this_pixel_color == (255,255,255):
   if this_pixel_row > 0:
    this_pixel_row = this_pixel_row - 1 
    this_pixel_color = Mond1_pixels[this_pixel_column,this_pixel_row]
   else: 
    this_pixel_color = (0,0,0)
    this_pixel_row = this_pixel_row - 1 
  top_white_row = this_pixel_row+1

  ###Grow right
  this_pixel_row = rand_row
  this_pixel_column = rand_col
  this_pixel_color = Mond1_pixels[this_pixel_column,this_pixel_row]
  while this_pixel_color == (255,255,255):
   if this_pixel_column < (mond_size_x - 1):
    this_pixel_column = this_pixel_column + 1 
    this_pixel_color = Mond1_pixels[this_pixel_column,this_pixel_row]
   else:
    this_pixel_color = (0,0,0)
    this_pixel_column = this_pixel_column + 1  
  right_white_column = this_pixel_column-1

  ###Grow left
  this_pixel_row = rand_row
  this_pixel_column = rand_col
  this_pixel_color = Mond1_pixels[this_pixel_column,this_pixel_row]
  while this_pixel_color == (255,255,255):
   if this_pixel_column > 0:  
    this_pixel_column = this_pixel_column - 1
    this_pixel_color = Mond1_pixels[this_pixel_column,this_pixel_row]
   else:
    this_pixel_color = (0,0,0)
    this_pixel_column = this_pixel_column - 1  
  left_white_column = this_pixel_column+1
  
  ###Pick field color
  this_color = random.choice(final_palette)

  ###Fill field
  for i in range(top_white_row,bottom_white_row+1):
   for j in range(left_white_column,right_white_column+1):
    #Mond1_pixels[j,i] = random.choice(avail_colors) #This is freaky
    Mond1_pixels[j,i] = this_color

  total_fields = total_fields + 1

  imagename = "Mond"+str(imagecounter)+".png"
  Mond1.save(imagename,'PNG') 
  imagecounter = imagecounter + 1

Some examples...

First, a 50 pixel by 50 pixel image.

500 by 500:

And something for Christmas:

2 comments:

  1. Hello, do you still have your tutorial for viewing light curves in python?
    Thanks

    ReplyDelete
    Replies
    1. I've put it back up. It's pretty out-of-date; try astropy in place of PyFITS. It should work about the same.

      Delete