We have the data that we need to begin building the map for our report. Our approach will be the following steps:
These tasks will all be accomplished using the PIL Image
and ImageDraw
modules:
# Convert the numpy array back to an image relief = Image.fromarray(shaded).convert("L") # Smooth the image several times so it's not pixelated for i in range(10): relief = relief.filter(ImageFilter.SMOOTH_MORE) log.info("Creating map image") # Increase the hillshade contrast to make # it stand out more e = ImageEnhance.Contrast(relief) relief = e.enhance(2) # Crop the image to match the SRTM image. We lose # 2 pixels during the hillshade process base = Image.open(osm_img + ".jpg").crop((0, 0, w-2, h-2)) # Enhance base map contrast before blending e = ImageEnhance.Contrast(base) base = e.enhance(1) # Blend the the map and hillshade at 90% opacity topo = Image.blend(relief.convert("RGB"), base, .9) # Draw the GPX tracks # Convert the coordinates to pixels points = [] for x, y in zip(lons, lats): px, py = world2pixel(x, y, w, h, bbox) points.append((px, py)) # Crop the image size values to match the map w -= 2 h -= 2 # Set up a translucent image to draw the route. # This technique allows us to see the streets # and street names under the route line. track = Image.new('RGBA', (w, h)) track_draw = ImageDraw.Draw(track) # Route line will be red at 50% transparency (255/2=127) track_draw.line(points, fill=(255, 0, 0, 127), width=4) # Paste onto the base map using the drawing layer itself # as a mask. topo.paste(track, mask=track) # Now we'll draw start and end points directly on top # of our map - no need for transparency topo_draw = ImageDraw.Draw(topo) # Starting circle start_lon, start_lat = (lons[0], lats[0]) start_x, start_y = world2pixel(start_lon, start_lat, w, h, bbox) start_point = [start_x-10, start_y-10, start_x+10, start_y+10] topo_draw.ellipse(start_point, fill="lightgreen", outline="black") start_marker = [start_x-4, start_y-4, start_x+4, start_y+4] topo_draw.ellipse(start_marker, fill="black", outline="white") # Ending circle end_lon, end_lat = (lons[-1], lats[-1]) end_x, end_y = world2pixel(end_lon, end_lat, w, h, bbox) end_point = [end_x-10, end_y-10, end_x+10, end_y+10] topo_draw.ellipse(end_point, fill="red", outline="black") end_marker = [end_x-4, end_y-4, end_x+4, end_y+4] topo_draw.ellipse(end_marker, fill="black", outline="white") # Save the topo map topo.save("{}_topo.jpg".format(osm_img))
While not saved to the filesystem, the hillshaded elevation looks as follows:
The blended topographic map looks like the following screenshot:
While hillshade mapping gives us an idea of the elevation, it doesn't' give us any quantitative data. To get more details, we'll create a simple elevation chart.