画像×視線データの可視化(個別データの解析)
📌はじめに
Eye Tracking(視線追跡)デバイスで取得した視線データをPythonで処理し、
ユーザーが広告の「どこ」を「どれくらい」見ていたのかを可視化する方法を紹介します。
視線データを活用すれば、画面上でユーザーの関心が集まるエリアを 定量的に把握 できます。
本記事では、視線の座標情報と滞在時間をもとに、広告画像の上へ 視線の軌跡や注目ポイントを重ね描画する手法 を解説します。
視線の時間と順番をマーカーで可視化した例
(マーカーの大きさ=見ていた時間、番号=見た順番)
❓Eye Tracking(アイ・トラッキング)とは❓
ユーザーが「どこを見ているか」を計測する技術。
専用デバイスやカメラで目の動き・視線位置をリアルタイムに捉えます。
広告やUI/UX研究、学習行動分析など幅広い分野で利用されています。
📌使用するデータ
-
視線データ :
sample.csv
ユーザーの視線位置と、その場所に「どれくらいの時間」注目したかを記録したデータです。
実験では、動画の途中で広告を表示し、
興味がある部分はじっと見てもらい、興味がなければ視線を外してもらいました。
sample.csv
-
広告画像 :
fish.png
(サイズ: 1360×840 ピクセル)
分析対象となる広告画像です。
📌コード解説
#=============================================
# 0.ライブラリ
#=============================================
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.image as mpimg
import japanize_matplotlib
#=============================================
# 1.入力データ読み込み
#=============================================
df = pd.read_csv("サンプル.csv",encoding='UTF-8')
#=============================================
# 2.近い点をまとめる関数(前の点と距離20以内なら同じ座標に)
#=============================================
def merge_close_points(x, y, threshold=20):
# 近い点をまとめる
merged_x = []
merged_y = []
for i in range(len(x)):
if i == 0:
merged_x.append(x[i])
merged_y.append(y[i])
else:
dx = x[i] - merged_x[-1]
dy = y[i] - merged_y[-1]
dist = np.sqrt(dx*dx + dy*dy)
if dist <= threshold:
merged_x.append(merged_x[-1])
merged_y.append(merged_y[-1])
else:
merged_x.append(x[i])
merged_y.append(y[i])
# 連続するグループ番号の付与
group_numbers = []
group_id = 0
for i in range(len(merged_x)):
if i == 0:
group_numbers.append(group_id)
else:
if merged_x[i] != merged_x[i-1] or merged_y[i] != merged_y[i-1]:
group_id += 1
group_numbers.append(group_id)
return merged_x, merged_y, group_numbers
#=============================================
# 3.座標リスト
#=============================================
merged_x, merged_y, group_numbers = merge_close_points(df['position_x'], df['position_y'])
0.ライブラリ
-
pandas
: CSVの読み込みやデータ処理に使用 -
numpy
: 数値計算や距離の計算に使用 -
matplotlib.pyplot
: グラフ描画に使用 -
matplotlib.image
: 画像の読み込みに使用 -
japanize_matplotlib
: グラフで日本語を正しく表示するために使用
1.入力データ読み込み
-
sample.csv
を読み込みます
2. 近い点をまとめる関数
-
merge_close_points
: 視線座標リスト (x
,y
) を入力として受け取り、
まとめた座標 (merged_x, merged_y
) とグループ番号 (group_numbers
) を
出力する関数
merge_close_points の役割と仕組み
目的
視線データはノイズや揺れで座標が細かくバラけがちです。
隣接する点同士が20ピクセル以内なら「同じ注目ポイント」とみなし、まとめています。
動作
前の点と現在の点の距離を計算し、閾値以下なら前の座標に揃えます。
座標が変わったときにグループ番号を更新し、同じ場所を見ていた点をひとまとまりに扱います。
なぜ20ピクセルなの❓
実際の視線は微妙にぶれるため、細かい揺れを無視するための基準として20ピクセル程度を採用。
ただし画面サイズやデータ特性によって最適値は変わるため、環境に応じて調整可能です。
3.座標リスト
-
merged_x, merged_y
: まとめ後の座標リスト -
group_numbers
: 連続して同じ場所を見た点に同じ番号を付与し、滞在時間集計や可視化に利用できる
group_numbers の活用イメージ
連続した同じ座標に属する点をまとめて扱えるので、滞在時間の集計や色分けに利用できます。
可視化時に同じ注目エリアとして強調できるメリットがあります。
#=============================================
# 4. 画像読み込みと視線軌跡描画のポイント
#=============================================
img = mpimg.imread("fish.png")
plt.figure(figsize=(13.8, 8.6))
plt.imshow(img)
#=============================================
# 5. 視線軌跡と点の描画
#=============================================
# 軌跡の線(黒)
plt.plot(merged_x, merged_y, color='black', linewidth=1)
# 点の大きさと色
sizes = df['time'] * 10
colors = df['time']
scatter = plt.scatter(merged_x, merged_y, s=sizes, c=colors, cmap='viridis', alpha=0.8)
plt.colorbar(scatter, label='time')
#=============================================
6. 軸設定とグループ番号表示
#=============================================
plt.xlim(0, img.shape[1])
plt.ylim(img.shape[0], 0) # Y軸反転
plt.xlabel("position_x")
plt.ylabel("position_y")
plt.title("視線軌跡 with Gradient Color and Labels")
for x, y, g, s in zip(merged_x, merged_y, group_numbers, sizes):
fontsize = np.sqrt(s) # 面積の平方根を文字サイズに
plt.text(x, y, str(g), color='red', fontsize=fontsize, ha='center', va='center')
plt.show()
4. 画像読み込みと表示
-
img = mpimg.imread("fish.png")
: 分析対象の広告画像を読み込み -
plt.figure(figsize=(13.8, 8.6))
: 描画領域のサイズを設定 -
plt.imshow(img)
: 画像を背景として表示
補足
-
mpimg.imread
で広告画像を読み込み、plt.imshow
で背景として表示 - 描画領域のサイズを画像の縦横比に合わせて調整
- この段階ではまだ視線の軌跡や点は表示されていません
5. 視線軌跡と点の描画
-
plt.plot(merged_x, merged_y, color='black', linewidth=1)
: 視線軌跡を線で描画 -
plt.scatter(merged_x, merged_y, s=sizes, c=colors, cmap='viridis', alpha=0.8)
: 視線点を描画-
sizes = df['time'] * 10
: 点の大きさは滞在時間に比例 -
colors = df['time']
: 点の色は滞在時間に応じて変化 -
alpha=0.8
: 重なっても見やすくする
-
-
plt.colorbar(scatter, label='time')
: 滞在時間の凡例を表示
補足
-
plt.plot
で軌跡(線)を黒色で描画 -
plt.scatter
で視線の位置を点として描き、大きさと色で滞在時間を表現 - カラーマップ
viridis
とplt.colorbar
で注目度を視覚化
6. 軸設定とグループ番号表示
-
plt.xlim(0, img.shape[1])
/plt.ylim(img.shape[0], 0)
: 画像座標系に合わせる(Y軸反転) -
plt.xlabel("position_x")
/plt.ylabel("position_y")
/plt.title(...)
: 軸ラベルとタイトル設定 - 点の中心にグループ番号を表示
❓なぜY軸を反転しているのか❓
- 画像データは左上が原点で、Y軸の数値は下方向に増える
- matplotlibの座標系は左下が原点で、Y軸は上方向に増える
-
plt.ylim(img.shape[0], 0)
で反転させることで、画像と視線点の位置を正しく対応
点の大きさ・色で滞在時間を表現している理由
- 長く注目した点は大きく、色も濃くして目立たせる
-
alpha=0.8
にして、点が重なっても見やすくする
グループ番号を点の中心に表示する工夫
-
group_numbers
で同じ注目エリアをグルーピング - 文字サイズは点の大きさの平方根で調整し、バランスよく表示
7. 可視化結果のまとめ
- 今回は1人分の視線データを、広告画像上に軌跡と注目点として可視化しました。
- 点の大きさ・色で滞在時間を表現し、グループ番号で同じ注目エリアを識別可能です。
- この手法により、ユーザーがどの部分を注目したか、注目の強弱、順序を直感的に把握できます。
補足
- 黒い線で視線軌跡を表示することで、どの順番で画面を見たかがわかる
- 点の大きさや色で滞在時間を表すことで、ユーザーの注目度を可視化
- グループ番号を表示することで、視線のまとまり(注目エリア)が明確になる
📌まとめ
本記事ではPythonを使って1人分の視線データを広告画像の上に重ね、注目ポイントを可視化する手法を紹介しました。
次回は複数ユーザーの視線データを画像上に重ねて表示し、全体の注目傾向を把握する方法を紹介します。
📌参考リンク・素材について
画像素材
掲載している画像素材は「いらすとや」さんのものを加工して使っています。
GitHubリポジトリ
本記事で紹介したコードやサンプルデータはこちらのリポジトリで公開しています。
https://github.com/iwakazusuwa/image-gaze-visualizer-mit-license
Discussion