Where's my Voi scooter: [9] Masking scooter heatmap on the map using Python PIL module

Where's my Voi scooter: [9] Masking scooter heatmap on the map using Python PIL module


3 min read

In this blog, I plan to incorporate the map into the heatmap made in the previous blog post, because, with only the heatmap, you can see which coordinates have a lot of scooters, but you have to reference the map with the coordinates, which is inconvenient. So I want to put the information on the Heatmap directly on the map so that the information is shown clearly.


Overlapping image

To overlap the image of the map and the heatmap, I need to find out how to have a half-transparent image on top of another image.

I first have to make an image transparent, I do that by using the putalpha(128) to make an image half transparent. It works by putting an alpha, or transparency level of 128 on that image. An alpha level of 0 means completely transparent, and level 255 means completely opaque. So 128 is in the middle, hence half-transparent.

Then I tried using image.paste(another_image) to put the half-transparent image on top of the other. but what happened is the image complete overwrites the other. what I needed was alpha_composite. For testing, I alpha composited the half-transparent map on top of the sat.

I created this map_img by getting the four coordinates I used for the range of the heatmap. and Taking a screenshot with exactly the four corners.


sat_map 2.png

from PIL import Image
map_img = Image.open('img/map.png')
sat_map = Image.open('img/sat_map.png')

result.png 3.png


Now I want to mask the heatmap image on the map image so that we can see the areas with a lot of scooters on the map. I wanted to use alpha composite like the last example, but I figured that using masking would be better. Image masking is putting image A on image B using image C as a guideline. I plan to put a dark image over the map, using the heatmap as a guideline. Places with more scooters will be darker so that we can tell where the scooters are on the map.

The function to do the masking is Image.composite(), it requires all images to have the same size. So I plan to use the size width 600 height 600 for all. I first make a background image of all white, resize the map image to the size of the heatmap using the thumbnail function, and paste it into the background. then I read the heatmap image and fix its size and convert it to L, which means greyscale for some reason. then I make a red image of all red, and I composite all of them together.

bg_img = Image.new("RGBA", (600, 600), 0)
map_img = Image.open('img/map.png')
map_img.thumbnail((474, 546), Image.ANTIALIAS)
bg_img.paste(map_img, (36, 21))
heatmap_img = Image.open('img/heatmap.png').resize((600, 600)).convert("L")
bk_img = Image.new("RGB", (600, 600), 255).convert("RGBA")
final_img = Image.composite(bk_img, bg_img, heatmap_img)

heatmap_img 4.png

The result is, for the places with more scooters, a red overlay will be on them, so we can tell where the scooters are focused.


What's next

In the next blog, I plan to analyse the Voi scooter data from July, since my data collecting program has been running for over a month already. I'm sure there will be interesting data collected.