Heat Map Effect

Hi all,

I intend to create an effect of heat map to detect the amount of people walking in an area like this:

55725-heatmap.jpg

But until now I only can draw pixels using vector2.

55779-heatmapintent.jpg

Anybody know any tutorial or information on how to do the effect?

Greetings.

A heatmap is usually drawn by taking all data in an area into account.

So lets say you have an array of Vector2/3 values which represents your recorded data. There are basically two ways to calculate the intensity for each pixel in your heatmap:

  • for each pixel you iterate through all of your data array and calculate the distance of the data point to the current pixel. The further away that data point is the less it’s addition to that pixel would be. A quadratic fall off ise quite common (simply use sqrMagnitude instead of magnitude). This however can take quite a while if you have a lot data.
  • the second way is a bit more optimised. You simply iterate through all your data points and use a square area around that point. Here you also would use a falloff from the center to the points which are further away. So you basically start with a pixel grid where each value is 0 and for each point in the data you increate all the points around that pixel.

In the end you should have an actual map where the hot areas have the highest value. Now just scale the values to fit in a 0-1 range and use a [Gradient][1] to give each pixel a color.

edit
This [question actually has been asked quite a few times][2] now. Did you actually search? ^^

2. edit

Here’s an example class i just written:

public class Heatmap
{
    private float[] samples;
    private float[] circle;
    private int width;
    private int height;
    private int radius;

    // returns the highest sample
    private float MaxValue
    {
        get
        {
            float v = 0f;
            for (int i = 0; i < samples.Length; i++)
                if (samples *> v)*

v = samples*;*
return v;
}
}

public Heatmap(int aWidth, int aHeight, int aRadius)
{
width = aWidth;
height = aHeight;
radius = aRadius;
samples = new float[aWidth * aHeight];
CreateCircleMap();
}
// creates our circle map that is “copied” into our map
void CreateCircleMap()
{
circle = new float[radius * radius * 4];
for(int x = -radius; x < radius; x++)
{
for(int y = -radius; y < radius; y++)
{
float l = (xx+yy) / (float)(radius*radius);
float v = 0f;
if (l < 1f)
v = 1f - l;
circle[x + radius + radius * 2 * y] = v;
}
}
}
public void AddPoint(Vector2 aPos)
{
int px = Mathf.RoundToInt(aPos.x);
int py = Mathf.RoundToInt(aPos.y);
for (int x = -radius; x < radius; x++)
{
for (int y = -radius; y < radius; y++)
{
int ix = px + x;
int iy = py + y;
if (ix < 0 || iy < 0 || ix >= width || iy >= height)
continue;
samples[ix + iy * width] += circle[x + radius + radius * 2 * y];
}
}
}

public Texture2D GetImage(Gradient aGradient)
{
Texture2D tex = new Texture2D(width, height,TextureFormat.ARGB32, false);
float scale = 1f / MaxValue;
Color[] colors = new Color[samples.Length];
for (int i = 0; i < colors.Length; i++)
colors = aGradient.Evaluate(samples * scale);
tex.SetPixels(colors);
tex.Apply();
return tex;
}
}
I haven’t tested the class but it mainly should show what i ment. So you create a new Heatmap with your desired width and height (which directly referes to the resulting image), and the size of the “circle” area that is added to the map for each point.
You can put your data into the heatmap with the “AddPoint” method where the point has to be already in pixel coordinates.
You can, at any time, create a texture out of the heatmap data by using “GetImage”. GetImage takes a Gradient as parameter. That Gradient specifies which areas will be black / transparent and which are white. Keep in mind that “0” represents nothing/ transparent (first color in the gradient) while “1” means the last color in the gradient.
AddPoint shouldn’t be too slow, however
*[1]: http://docs.unity3d.com/ScriptReference/Gradient.html*_
*[2]: Google

What you’re probably going to want to do is render to a down-sampled screen buffer, then blur it and scale it up to screen space. Then you can do the drawing like you have in the screenshot, but it will look like the desired effect.

Look up RenderTargets to learn how to render to a separate buffer.