ファンサービスの”当たり判定”を知りたい【可視化編】

## あらすじ

ここまででファンサービス(以降ファンサ)の当たり判定を可視化するために，
ファンサデータの収録方法や，評価方法などを検討してきた．

ファンサが当たったかどうかのラベルが付与されたので，
あとは可視化していくのみ．

https://qiita.com/Killinneko/items/5ae7b86180ecb5961096

https://qiita.com/Killinneko/items/6b68af94fd5c3b0fdb5c

https://qiita.com/Killinneko/items/debe0bbc90c714626581


## 概要

前回，以下のようなファンサが含まれる動画データに対して主観の4段階評価でラベルを付与した．
位置情報と当たり判定ラベルが付与されているので，今回はラベルと位置の関係を可視化する．

| パラメータ | 値 | 
| - | - | 
| 演者からカメラまでの距離(m) | 6, 18　(2種) | 
| ファンサの角度(°) | 45,35,25,15,10,5,0,-5,-10,-15,-25,-35,-45　(13種) |
| ファンサの種類 | 手を振る，指をさす，投げキッス (3種) |

位置と値を可視化するためにヒートマップを利用する．
各ファンサの当たり判定をヒートマップで可視化することで，比較できると考えた．
pythonを利用してヒートマップで表示する方法は以下で紹介している．

https://qiita.com/Killinneko/items/8b520c26453c395168c6

上記のプログラムをそのまま利用するためには，極座標の位置情報をユークリッド空間に戻して表示する必要がある．

## 可視化する

### 極座標からユークリッド空間座標に変換

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3600683/403113c8-6be6-2f8f-b56c-51104d5badf5.png)

演者とカメラ間を固定し，ファンサの角度を変えて撮影をした．
そのため極座標の情報として，奥行きRm(=6m,18m) と ファンサの角度θm(=-45°~45°)が利用できる．
これをユークリッド空間座標(X,Y)に変換するには，(Rsinθ, Rcosθ)として計算をする．

エクセルシートで一覧を作ると以下のようになった．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3600683/b111b06b-7979-35d2-2d33-803c4cdb4790.png)

### 散布図・ヒートマップで表示

前回作ったプログラムを流用できるように，値はcsv形式で読み込んで配列を作る形式にする．

```python:ライブラリインポートとcsv読み込み
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colors as mcolors
from scipy.interpolate import griddata
import csv

plt.rcParams['font.family'] = 'MS Gothic'  # 日本語フォントを指定

# CSVから読み込み
x = []
y = []
wavehand = []
pointfinger = []
throwkiss = []

with open('../label.csv', newline='',encoding='utf-8-sig') as csvfile:  
    csv_reader = csv.reader(csvfile)
    next(csv_reader)
    for row in csv_reader:
        x.append(float(row[0]))
        y.append(float(row[1]))
        wavehand.append(int(row[2]))
        pointfinger.append(int(row[3]))
        throwkiss.append(int(row[4]))

print(x[0], y[0], wavehand[0], pointfinger[0], throwkiss[0])
---
>5.909 -1.042 2 1 1
```
うまく1行目の値が読み込まれているのを確認した．

次は散布図を表示する．

```python: 散布図としてプロット

data = wavehand # ここに任意のラベルを入れる

plt.scatter(x, y, c=data, cmap='Blues', s=10)  
plt.colorbar() 
plt.scatter([x[i] for i in range(len(data)) if data[i] == 1], 
            [y[i] for i in range(len(data)) if data[i] == 1],
            color='red', s=20, label='当たってない',marker='x')

plt.scatter(0, 0, marker='*', color='black', s=100, label='演者')

plt.xlim(-3,25 )
plt.ylim(-14,14) 
plt.xlabel('奥行き(m)')
plt.ylabel('横幅(m)')
plt.title('投げキッス')
plt.legend(loc='upper left')  
plt.show()
```

出力するとこのような感じ．
デフォルトだと1が白で出力されていなかったので，追加で表示するようにした．
あとは，「実空間上と同じ」が重要なので軸の比率が1:1になるように調整した．

![手を振る_散布図.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3600683/0e90f360-7ece-f7d6-80e0-b0d5044819f4.png)

次はヒートマップを表示する．

```python:ヒートマップを表示
# 補完対象となる点座標を作成
xi = np.linspace(min(x), max(x), 100)
yi = np.linspace(min(y), max(y), 100)
xi, yi = np.meshgrid(xi, yi)

# 点間の補完を行う
zi = griddata((x, y), data, (xi, yi), method='linear')


# プロット
plt.figure(figsize=(8, 6))
plt.imshow(zi, extent=(min(x), max(x), min(y), max(y)), origin='lower', cmap='Blues')
plt.colorbar()  
plt.scatter(0, 0, marker='*', color='black', s=100, label='演者')
plt.xlim(-3,25 )
plt.ylim(-14,14) 
plt.xlabel('奥行き(m)')
plt.ylabel('横幅(m)')
plt.title("投げキッス")
plt.legend(loc='upper left')  # 凡例を追加
plt.show()
```

ヒートマップを表示するとこんな感じ．

![手を振る_ヒートマップ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3600683/ed7760cd-f2eb-e3c5-d9f1-7a9c42772ea0.png)

色が濃い部分がファンサの"当たり判定"とされる部分である．

これで分析の準備ができた．

## 分析・考察

### ヒートマップを並べてみる

分析しやすいように中心線を引いてみた．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3600683/8fffa245-68fd-4d9e-bee4-b01183625f6b.png)

ファンサの当たり判定を表示すると，見た感じ**違いは出ている．**
手を振る当たり判定が大きく，次に指をさす，投げキッスの順番で小さくなっている(幅が狭くなっている)．
全てに共通しているのは，演者から観客を見て左側の方が当たり判定がある．

### 手を振るファンサの当たり判定が大きい理由

これは，「身振りの大きさ」に関連して大きくなっているのではないかと思う．
身振りが大きいと，誰に対して送っているものかわからない(=誰にでも届く可能性はある)からではないかと考える．
経験として，前に中途半端な知り合いが手を振ってきたら「あっ，自分かな？」となる現象がある．
(自分の後ろにいる人に手を振っていて恥を書くというオチのやつ)
手を振る動作が自分に対して送られている動作かどうかわからないからこそ起こることであり，逆にそれが，ファンサが「自分にも当たった」と思う人が多くなる理由だと思う．

これを証明するために身振りが大きめのファンサを評価して実証する必要がある．

### 左側の当たり判定が大きい理由

全てに共通して，演者が観客を見て左側の当たり判定が大きいという結果が出た．
全て同じ方向なのは，「すべてのファンサを右手のみで実施したから」という理由で，
使った手と逆なのは，「顔が隠れる・動作が違う向きでファンサを当たった気にならない」という理由なのかと考えた．

例として，手を振る動作を図に起こした．(実際は眼鏡をかけていないが，正面を理解するために描写)
正面から見ると右手を振っているだけのように見えるが，右側から見ると，顔の一部が隠れてしまう．
逆に左側から見ると，顔が見えかつ手を振る動作が見えるのでファンサが当たった気になるのではないかと考えた．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3600683/f0a81f92-020d-e763-4573-a79cbc8ffab9.png)


投げキッス・指をさす動作は体側に腕を持ってきてまっすぐ正面に腕を伸ばすようにしているため，
外側(右側)の観客からは，指をさされた気にならないのではないかと考える．

これを証明するためには，左側でファンサを行い比較する必要がある．

### 指をさすと投げキッスの範囲の違い

実験前は同じくらいの当たり判定かと思っていたが，わずかに投げキッスの方が当たり判定が狭いことが分かった．この理由は**動作が完了するまでの予備動作**にあると思われる．

指をさす動作は，体のみぞおち付近を右手の指をさした状態のまま，正面に肘を伸ばす形で動作を行う．
その場合，指をさされたと感じるのは，完了後の指をさされた人だけでなく予備動作の中でさされた人も含まれているように思う．

一方，投げキッスは手を唇に持っていきそのまま正面に手を伸ばす．
この動作だと予備動作の中で刺されたと感じる人は少ないため，指をさすと投げキッスに違いが出たと思われる．

指をさす際の予備動作が当たり判定に含まれるかどうかを検証するためには，
手を下に下げた状態でまっすぐ正面に指をさした際のファンサと比較することで，
違いが分かるのではないかと思われる．

## まとめ

今回，ファンサの当たり判定を検証した結果，
身振りの大きさがファンサの当たり判定に関係しており，身振りが大きければファンサの範囲も大きいと考察した，また，ファンサの予備動作も含めて当たり判定があると推測した．

次回で追加収録をする際は，**左右・予備動作を良く考慮**し，前もって一定規格のファンサを作って置く必要があると感じた．

自分の中にあった大きな謎が一つ解消する兆しができて本当に良かったと思う．
時間があれば引き続き調査したり論文として完成させたいと思う．

論文として完成させる場合，厳密な環境・設定で実施する必要があるため，
他の人を巻き込んで実施する必要がある．