Package mosp_tools :: Package heatmap :: Module heatmap
[hide private]
[frames] | no frames]

Source Code for Module mosp_tools.heatmap.heatmap

  1  """Heatmap generation based in simulation logs and a background map 
  2   
  3  inspired by http://www.jjguy.com/heatmap/ which based on http://code.google.com/p/gheat/ 
  4   
  5  """ 
  6   
  7  import sys 
  8  sys.path.append("../..") 
  9  from mosp.geo.utm import long_to_zone, latlong_to_utm 
 10   
 11  from math import sqrt 
 12  from os import spawnvp, P_WAIT 
 13  from PIL import Image, ImageChops, ImageEnhance, ImageDraw, ImageFont, ImageColor 
 14   
 15  from logfilereader import accumulated_read 
 16  import colorschemes 
 17   
 18  __author__ = "B. Henne" 
 19  __contact__ = "henne@dcsec.uni-hannover.de" 
 20  __copyright__ = "(c) 2011, DCSec, Leibniz Universitaet Hannover, Germany" 
 21  __license__ = "MIT license" 
 22   
 23   
24 -class Heatmap(object):
25 """A generator for heatmap images based on simulation log data. 26 @author: B. Henne 27 """ 28
29 - def __init__(self, mapfilename, minlon, maxlon, minlat, maxlat, dotsize=30):
30 """Initialize the heatmap generation object.""" 31 # map(ping) configuration 32 self.mapfile = mapfilename #: filename of underlay map from osm export 33 self.minlon = minlon #: min longitude from osm png export 34 self.maxlon = maxlon #: max longitude from osm png export 35 self.minlat = minlat #: min latitude from osm png export 36 self.maxlat = maxlat #: max latitude from osm png export 37 # calculate values 38 self.x_min, self.y_min = latlong_to_utm(self.minlon, self.minlat) 39 self.x_max, self.y_max = latlong_to_utm(self.maxlon, self.maxlat) 40 self.width = abs(self.x_max - self.x_min) 41 self.height = abs(self.y_max - self.y_min) 42 # setup fonts 43 font_path = "/usr/share/fonts/" 44 self.sans18 = ImageFont.truetype (font_path+'dejavu/DejaVuSansMono-Bold.ttf', 18) 45 self.sans12 = ImageFont.truetype (font_path+'dejavu/DejaVuSansMono-Bold.ttf', 12) 46 # setup images: dot 47 self.dotsize = dotsize 48 self.dot = self.__dotImage(self.dotsize) 49 # setup images: backgroud map 50 self.map = Image.open(self.mapfile) 51 self.mapsize = self.map.size 52 if self.map.mode != 'RGBA': 53 self.map = self.map.convert('RGBA') 54 draw = ImageDraw.Draw(self.map) 55 draw.text((self.mapsize[0]-300, self.mapsize[1]-30), 56 '(c) OpenStreetMap contributors, CC-BY-SA', 57 font=self.sans12, fill=ImageColor.colormap['darkgrey']) 58 draw.rectangle([(16,10),(80,30)], fill=ImageColor.colormap['lightgray']) 59 del draw
60
61 - def _colorize(self, img, colors, opacity):
62 """Use the colorscheme selected to color the image densities. 63 64 heatmap.py v1.0 20091004. from http://www.jjguy.com/heatmap/""" 65 finalVals = {} 66 w,h = img.size 67 for x in range(w): 68 for y in range(h): 69 pix = img.getpixel((x,y)) 70 rgba = list(colors[pix[0]][:3]) #trim off alpha, if it's there. 71 if pix[0] <= 254: 72 alpha = opacity 73 else: 74 alpha = 0 75 rgba.append(alpha) 76 img.putpixel((x,y), tuple(rgba))
77
78 - def __dotImage(self, size):
79 """Returns a image of the dot that is used for drawing heatmap.""" 80 dotimg = Image.new("RGB", (size,size), 'white') 81 md = 0.5*sqrt( (size/2.0)**2 + (size/2.0)**2 ) 82 for x in range(size): 83 for y in range(size): 84 d = sqrt( (x - size/2.0)**2 + (y - size/2.0)**2 ) 85 rgbVal = int(200*d/md + 50) 86 rgb = (rgbVal, rgbVal, rgbVal) 87 dotimg.putpixel((x,y), rgb) 88 return dotimg
89
90 - def __translate(self, xy):
91 """Translates x,y coordinates into pixel offsets of a map.""" 92 # translation 93 _x = float(xy[0]) - self.x_min 94 _y = float(xy[1]) - self.y_min 95 # scaling 96 _x = int(_x / self.width * self.mapsize[0]) 97 _y = self.mapsize[1] - int(_y / self.height * self.mapsize[1]) 98 # translation for dot size 99 _x = _x - self.dotsize / 2 100 _y = _y - self.dotsize / 2 101 return (_x,_y)
102
103 - def generate(self, logfilename, delimiter, t, x, y, t_start, t_end, step, reset_dotlayer_every_step=False):
104 """Generates the heapmap PNG image files. 105 106 @param logfilename: name of csv-formated log file 107 @param delimiter: delimiter between columns in csv log file 108 @param t: number of log file's column containing time 109 @param x: number of log file's column containing x-value 110 @param y: number of log file's column containing y-value 111 @param t_start: start of output time interval 112 @param t_end: end of output time interval 113 @param step: size/length of a log accumulation step 114 @param reset_dotlayer_every_step: draw second heatmap over first one etc. or clear for each image 115 """ 116 dotlayer = Image.new('RGBA', self.mapsize, 'white') 117 for timestep, timestepdata in accumulated_read(logfilename, delimiter, t, x, y, t_start, t_end, step=step): 118 for xy in timestepdata: 119 dot = Image.new('RGBA', self.mapsize, 'white') 120 dot.paste(self.dot, self.__translate(xy)) 121 dotlayer = ImageChops.multiply(dotlayer, dot) 122 123 heatmask_color = dotlayer.copy() 124 self._colorize(heatmask_color, colorschemes.schemes['fire'], 200) 125 draw = ImageDraw.Draw(heatmask_color) 126 draw.text((10,10), str('% 4d' % timestep), font=self.sans18, fill=ImageColor.colormap['black']) 127 del draw 128 #img.save('/tmp/heatmap-overlay-%4s' % timestep) 129 Image.composite(heatmask_color, self.map, heatmask_color).save('/tmp/demo-heatmap1-%05d.png' % timestep) 130 if reset_dotlayer_every_step == True: 131 dotlayer = Image.new('RGBA', self.mapsize, 'white')
132
133 - def mencode_video(self, location, files, filetype, videofile):
134 """[Bad Video Quality] Encodes a set of image files to a video file using mencoder. 135 136 Better use: 137 1. mencoder mf://PNG/heatmap1*.png -mf type=png:w=780:h=600:fps=30 -o /dev/null -ovc x264 -x264encopts pass=1:bitrate=1200:bframes=1:me=umh:partitions=all:trellis=1:qp_step=4:qcomp=0.7:direct_pred=auto:keyint=300 -vf crop=768:576:0:0 138 2. mencoder mf://PNG/heatmap1*.png -mf type=png:w=780:h=600:fps=30 -o heatmap1.avi -ovc x264 -x264encopts pass=2:bitrate=1200:bframes=1:me=umh:partitions=all:trellis=1:qp_step=4:qcomp=0.7:direct_pred=auto:keyint=300 -vf crop=768:576:0:0""" 139 command = ('mencoder', 140 'mf://%s%s' % (location, files), 141 '-mf', 142 'type=%s:w=%s:h=%s:fps=30' % (filetype, self.mapsize[0], self.mapsize[1]), 143 '-ovc', 144 'lavc', 145 '-lavcopts', 146 'vcodec=mpeg4', 147 '-oac', 148 'copy', 149 '-o', 150 '%s%s' % (location, videofile)) 151 spawnvp(P_WAIT, 'mencoder', command)
152 153 154 if __name__ == '__main__': 155 print 'Initializing heatmap.' 156 h = Heatmap('data/demo-heatmap_map.png', -87.6405, -87.60125, 41.866258, 41.88875, dotsize=10) 157 print 'Generating image files.' 158 h.generate('data/demo-heatmap.log', ' ', 1, 3, 4, 42000, 42048, step=12, reset_dotlayer_every_step=True) 159 # print 'Generating video.' 160 # h.mencode_video('/tmp/', 'demo-heatmap1*.png', 'png', 'demo-heatmap1.avi') 161