Pastebin launched a little side project called HostCabi.net, check it out ;-)Don't like ads? PRO users don't see any ads ;-)
Guest

collage.py

By: goakley on Feb 15th, 2014  |  syntax: Python  |  size: 4.33 KB  |  hits: 41  |  expires: Never
download  |  raw  |  embed  |  report abuse  |  print
Text below is selected. Please press Ctrl+C to copy to your clipboard. (⌘+C on Mac)
  1. #!/usr/bin/env python3
  2.  
  3. import glob
  4. from PIL import Image
  5. from random import shuffle
  6.  
  7. MAXSIZE = (640,480)
  8.  
  9. images = []
  10.  
  11. imagefilelist = list(glob.glob("images/*.*"))
  12.  
  13. for imagefile in imagefilelist:
  14.     image = Image.open(imagefile)
  15.     image.thumbnail(MAXSIZE)
  16.     images.append(image)
  17.  
  18. images.sort(key=lambda image: image.size[0] * image.size[1], reverse=True)
  19. #shuffle(images)
  20.  
  21. class Rectangle:
  22.     def __init__(self, x1, y1, x2, y2, image=None):
  23.         self.x1 = x1
  24.         self.x2 = x2
  25.         self.y1 = y1
  26.         self.y2 = y2
  27.         self.width = x2 - x1
  28.         self.height = y2 - y1
  29.         self.area = self.width * self.height
  30.         self.ratio = self.width / self.height
  31.         self.image = image
  32.     def __eq__(self, other):
  33.         return (self.x1 == other.x1 and self.y1 == other.y1 and
  34.                 self.x2 == other.x2 and self.y2 == other.y2)
  35.     def __hash__(self):
  36.         return (self.x1, self.y1, self.x2, self.y2).__hash__()
  37.     def __repr__(self):
  38.         return "(" + str(self.x1) + " " + str(self.y1) + " " + str(self.x2) + " " + str(self.y2) + ")"
  39.     def intersects(self, other):
  40.         if type(other) == Rectangle:
  41.             return (self.x1 < other.x2 and self.x2 > other.x1 and
  42.                     self.y1 < other.y2 and self.y2 > other.y1)
  43.         for r in other:
  44.             if self.intersects(r):
  45.                 return True
  46.         return False
  47.     def grow(self, other):
  48.         if type(other) != Rectangle:
  49.             raise Exception()
  50.         return Rectangle(self.x1 if self.x1 < other.x1 else other.x1,
  51.                          self.y1 if self.y1 < other.y1 else other.y1,
  52.                          self.x2 if self.x2 > other.x2 else other.x2,
  53.                          self.y2 if self.y2 > other.y2 else other.y2)
  54.  
  55.  
  56. OFFSET = 16
  57. offset = OFFSET
  58.  
  59. rectangles = []
  60. overall = None
  61. inflections = set([])
  62. c = 0
  63. for image in images:
  64.     if not len(rectangles):
  65.         rectangles.append(Rectangle(0,0, image.size[0], image.size[1], image))
  66.         overall = Rectangle(0, 0, image.size[0], image.size[1])
  67.         inflections.update([(overall.x1-OFFSET, overall.y1-OFFSET),
  68.                             (overall.x2+OFFSET, overall.y1-OFFSET),
  69.                             (overall.x1-OFFSET, overall.y2+OFFSET),
  70.                             (overall.x2+OFFSET, overall.y2+OFFSET)])
  71.         continue
  72.     options = set([])
  73.     for point in inflections:
  74.         options.update([(point[0],point[1]),
  75.                         (point[0]-image.size[0],point[1]),
  76.                         (point[0],point[1]-image.size[1]),
  77.                         (point[0]-image.size[0],point[1]-image.size[1])])
  78.     potentials = []
  79.     for option in options:
  80.         testrect = Rectangle(option[0], option[1], option[0]+image.size[0], option[1]+image.size[1])
  81.         if testrect.intersects(rectangles):
  82.             continue
  83.         potentials.append(testrect)
  84.     #print("Overall:", overall)
  85.     smallestgrow = None
  86.     bestrect = None
  87.     shuffle(potentials)
  88.     for pot in potentials:
  89.         newgrow = overall.grow(pot)
  90.         if (smallestgrow is None) or (newgrow.width + newgrow.height < smallestgrow.width + smallestgrow.height):
  91.             if newgrow.ratio > 1.33:
  92.                 smallestgrow = newgrow
  93.                 bestrect = pot
  94.     bestrect.image = image
  95.     rectangles.append(bestrect)
  96.     #print("Best Match:", bestrect)
  97.     overall = smallestgrow
  98.     #print("New Overall:", overall)
  99.     inflections.update([(bestrect.x1-OFFSET, bestrect.y1-OFFSET),
  100.                         (bestrect.x2+OFFSET, bestrect.y1-OFFSET),
  101.                         (bestrect.x1-OFFSET, bestrect.y2+OFFSET),
  102.                         (bestrect.x2+OFFSET, bestrect.y2+OFFSET)])
  103.     c += 1
  104.     #if c == 1000:
  105.     #    break
  106.  
  107. minx = rectangles[0].x1
  108. miny = rectangles[0].y1
  109. for rectangle in rectangles:
  110.     if minx > rectangle.x1:
  111.         minx = rectangle.x1
  112.     if miny > rectangle.y1:
  113.         miny = rectangle.y1
  114. for rectangle in rectangles:
  115.     rectangle.x1 -= minx
  116.     rectangle.y1 -= miny
  117.     rectangle.x2 -= minx
  118.     rectangle.y2 -= miny
  119.  
  120. overall.x1 -= minx
  121. overall.y1 -= miny
  122. overall.x2 -= minx
  123. overall.y2 -= miny
  124.  
  125. final = Image.new("RGB", (overall.x2,overall.y2), (128,128,128))
  126.  
  127. for rectangle in rectangles:
  128.     final.paste(rectangle.image, (rectangle.x1, rectangle.y1))
  129.  
  130. final.save("/tmp/out.png")