· 

散布図からヒートマップを作成する(Python)

(著)山たー

 サンプリングした点から、点を中心としたガウシアンを重ね合わせ、ヒートマップを作る。使いどころがなさそうだが、注視点の視覚化に必要だったのでメモとして残しておく。

 

heatmap.pyのセットアップ

まず以下のサイトにアクセス

heatmap.py: create heatmaps in python

tgzかzipをダウンロード(heatmap-2.2.1.tar.gz 等)

 

インストールは

 $ cd heatmap-2.2.1; python setup.py install

とする。Python Imaging Library と Python 2.5+が必要。3系ではダメ。

 

2系が無い場合はanacondaで

conda create -n py27 python=2.7 anaconda

とかする。

 

PIL(Python Imaging Library)のインストールは

 pip install pillow

でOK

 

コード例1

exampleを改変。

import heatmap
from numpy.random import *

if __name__ == "__main__":    
    pts = [] #(x,y)の点を格納する配列 ← これに自分のデータを入れればok
    
    #テストデータとして、点をランダムに生成
    num_points=1000 #ランダムに生成する点の数
    for x in range(num_points):
        X=randn()
        Y=randn()
        pts.append((X,Y)) #正規分布の乱数

    monitor_size=(1024,1024) #画面サイズ
    hm = heatmap.Heatmap()
    img = hm.heatmap(
        points=pts, #点の配列(x,y)
        size=monitor_size,#画面サイズ
        dotsize=30, #ガウシアンのσ(標準偏差)に対応
        #area=((0, 0),(monitor_size[0], monitor_size[1])), #座標の設定
        scheme='classic', #スタイル(classic,fire    ,omg,pbj,pgaitch)
        opacity=200 #透明度
        )
    img.save("classic.png")

 

オプションは

 heatmap(self, points, dotsize=150, opacity=128, size=(1024, 1024), scheme='classic', area=None)
 |    points  -> an iteratable list of tuples, where the contents are the
 |               x,y coordinates to plot. e.g., [(1, 1), (2, 2), (3, 3)]
 |    dotsize -> the size of a single coordinate in the output image in
 |               pixels, default is 150px.  Tweak this parameter to adjust
 |               the resulting heatmap.
 |    opacity -> the strength of a single coordiniate in the output image.
 |              Tweak this parameter to adjust the resulting heatmap.
 |    size    -> tuple with the width, height in pixels of the output PNG
 |    scheme  -> Name of color scheme to use to color the output image.
 |               Use schemes() to get list.  (images are in source distro)
 |    area    -> Specify bounding coordinates of the output image. Tuple of 
 |               tuples: ((minX, minY), (maxX, maxY)).  If None or unspecified, 
 |               these values are calculated based on the input data.
 |
 |    Returns a PIL Image object.  Call .save(fname) to write to disk.

となっている。

 

例1の出力結果

ガウシアンに従う乱数をテストデータとしてプロットしてみる。

dotsize=30, scheme='classic'の場合

dotsize=80, scheme='fire'の場合

コード例2

import heatmap
import numpy as np

def random_a_b(a,b,num):
    return (b - a) * np.random.rand(num,2) + a

if __name__ == "__main__":    
    #テストデータとして、点をランダムに生成
    num_points=1000 #ランダムに生成する点の数
    pts=random_a_b(200,800,num_points) #(x,y)の点を格納する配列

    monitor_size=(1024,1024) #画面サイズ
    hm = heatmap.Heatmap()
    img = hm.heatmap(
        points=pts, #点の配列(x,y)
        size=monitor_size,#画面サイズ
        dotsize=40, #ガウシアンのσ(標準偏差)に対応
        area=((0, 0),(monitor_size[0], monitor_size[1])), #座標の設定
        scheme='classic', #スタイル(classic,fire,omg,pbj,pgaitch)
        opacity=200 #透明度
        )
    img.save("classic.png")

例2の出力結果

ちょっと分かりづらいが、画面サイズが1024x1024で200~800の範囲に点を打っている。

 

注視点分布の可視化

注視点データを可視化してみる。MIT Saliency Benchmarkにあるデータセット"CAT2000"を使ってみる。このデータセットは4000枚の画像を24人の被験者に5秒間見せた際のfixationを記録したものである。

 

fixation2heatmap.py

import heatmap
import scipy.io as sio
import numpy as np

#matdata全体の読み込み
matdata = sio.loadmat("./FIXATIONLOCS/Affective/001.mat")
fixLocs=matdata["fixLocs"]
#matファイルをメモリから消去する
matdata.clear()

#位置を取得
fixPos_tmp=np.where(fixLocs==1)
fixPos=np.zeros((369,2))
fixPos[:,0]=fixPos_tmp[1]
fixPos[:,1]=1080-fixPos_tmp[0]

#heatmap
monitor_size=(1920,1080) #画面サイズ
hm = heatmap.Heatmap()
img = hm.heatmap(
        points=fixPos, #点の配列(x,y)
        size=monitor_size,#画面サイズ
        dotsize=100, #ガウシアンのσ(標準偏差)に対応
        area=((0, 0),(monitor_size[0], monitor_size[1])), #座標の設定
        scheme='classic', #スタイル(classic,fire    ,omg,pbj,pgaitch)
        opacity=100 #透明度
        )
img.save("heatmap.png")

matファイルからfixationを読み込み、座標を取得した後、heatmapに変換している。

 

overlay.py

from PIL import Image
#background = Image.open('./FIXATIONMAPS/Affective/001.jpg').convert('RGB')
background = Image.open('./Stimuli/Affective/001.jpg')
foreground = Image.open('heatmap.png')

background.paste(foreground, (0, 0), foreground)
background.save("result.png")

PILで画像を重ねる。

 

結果

ちょっと見づらい気がしなくもない。

 

参考文献

tobii eyeXで測定した視覚情報のcsvファイルからヒートマップ画像を作成してみた

正直、この記事はほとんどこれを参考にして書いたが、自分用のメモということで