質問するログイン新規登録

回答編集履歴

3

d

2019/07/30 09:41

投稿

tiitoi
tiitoi

スコア21962

answer CHANGED
@@ -143,7 +143,8 @@
143
143
  print(np.allclose(std1, std2)) # True
144
144
  ```
145
145
 
146
+ > 30秒の動画があってR+G+B/3が大きいところほど強度が高いです(赤です)
146
- >
147
+ > しかしながら全体的に強度の変化もないので標準偏差は小さくなるはずです(青になる)
147
148
 
148
149
  ```python
149
150
  import matplotlib.pyplot as plt
@@ -156,8 +157,5 @@
156
157
  plt.show()
157
158
  ```
158
159
 
159
- > 30秒の動画があってR+G+B/3が大きいところほど強度が高いです(赤です)
160
- > しかしながら全体的に強度の変化もないので標準偏差は小さくなるはずです(青になる)
161
-
162
160
  標準偏差が高い = 赤とは限らないです。色は matplotlib で可視化した際のカラーマップをどう設定したかによります。
163
161
  例えば、質問の画像だと右側のカラーバーを見る限り、標準偏差が小さいと赤、大きいと青になっています。

2

d

2019/07/30 09:41

投稿

tiitoi
tiitoi

スコア21962

answer CHANGED
@@ -88,4 +88,76 @@
88
88
  ax.imshow(std)
89
89
 
90
90
  plt.show()
91
- ```
91
+ ```
92
+
93
+ ## 追記
94
+
95
+ > しかしながら出力画像を見てみると標準偏差ではないように思えます
96
+
97
+ 追記した方法だと計算結果が違うというご指摘でしょうか?
98
+ 一応、下記方法で最初に回答した方法 (方法1) と追記した方法 (方法2) で計算結果が一致することは確認しています。
99
+
100
+ ```python
101
+ import cv2
102
+ import numpy as np
103
+
104
+ cap = cv2.VideoCapture("vtest.avi")
105
+
106
+ # 方法1
107
+ ##################################
108
+ frames = []
109
+ while True:
110
+ ret, frame = cap.read()
111
+ if not ret:
112
+ break
113
+ frames.append(frame)
114
+ frames = np.array(frames)
115
+
116
+ std1 = frames.std(axis=(0, 3))
117
+
118
+ # 方法2
119
+ ##################################
120
+ cap = cv2.VideoCapture("vtest.avi")
121
+
122
+ w = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) # フレームの幅
123
+ h = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) # フレームの高さ
124
+ num_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT)) # フレーム数
125
+
126
+ frame_sum = np.zeros((h, w)) # 各画素の和を格納する配列
127
+ frame_squared_sum = np.zeros((h, w)) # 各画素の平方和を格納する配列
128
+
129
+ while True:
130
+ ret, frame = cap.read()
131
+ if not ret:
132
+ break
133
+ frame = frame.astype(float) # uint8 -> float (uint8 型で frame**2 すると、overflow するため)
134
+ frame_sum += frame.sum(axis=-1) # 和を計算する。
135
+ frame_squared_sum += (frame ** 2).sum(axis=-1) # 自乗和を計算する。
136
+
137
+ mean = frame_sum / (num_frames * 3)
138
+ var = frame_squared_sum / (num_frames * 3) - mean ** 2
139
+ std2 = np.sqrt(var)
140
+
141
+ ##################################
142
+ # 方法1 と 方法2 の計算結果が一致することを確認
143
+ print(np.allclose(std1, std2)) # True
144
+ ```
145
+
146
+ >
147
+
148
+ ```python
149
+ import matplotlib.pyplot as plt
150
+
151
+ # ヒートマップで描画する。
152
+ fig, ax = plt.subplots()
153
+ img = ax.imshow(std)
154
+ fig.colorbar(img)
155
+
156
+ plt.show()
157
+ ```
158
+
159
+ > 30秒の動画があってR+G+B/3が大きいところほど強度が高いです(赤です)
160
+ > しかしながら全体的に強度の変化もないので標準偏差は小さくなるはずです(青になる)
161
+
162
+ 標準偏差が高い = 赤とは限らないです。色は matplotlib で可視化した際のカラーマップをどう設定したかによります。
163
+ 例えば、質問の画像だと右側のカラーバーを見る限り、標準偏差が小さいと赤、大きいと青になっています。

1

d

2019/07/30 09:39

投稿

tiitoi
tiitoi

スコア21962

answer CHANGED
@@ -43,4 +43,49 @@
43
43
  plt.show()
44
44
  ```
45
45
 
46
- ![イメージ説明](ba452601b210881200219b9c0c385a97.png)
46
+ ![イメージ説明](ba452601b210881200219b9c0c385a97.png)
47
+
48
+ ## 追記
49
+
50
+ > 800×800だとメモリーエラーとなります。
51
+
52
+ 標準偏差を計算するのに必要なのは、各画素の和と自乗和だけなので、以下のようにすることでフレームの長さに関わらず、使用するメモリ量を固定できます。
53
+
54
+ 標準偏差は分散の平方根なので、分散を以下の分散公式で求めればよいです。
55
+ 式の導出はネット上に沢山情報があるので省略します。
56
+
57
+ [分散の意味と求め方、分散公式の使い方](https://sci-pursuit.com/math/statistics/variance.html)
58
+
59
+ ```python
60
+ import cv2
61
+ import matplotlib.pyplot as plt
62
+ import numpy as np
63
+
64
+ cap = cv2.VideoCapture("vtest.avi")
65
+
66
+ w = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) # フレームの幅
67
+ h = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) # フレームの高さ
68
+ num_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT)) # フレーム数
69
+
70
+ frame_sum = np.zeros((h, w)) # 各画素の和を格納する配列
71
+ frame_squared_sum = np.zeros((h, w)) # 各画素の平方和を格納する配列
72
+
73
+ while True:
74
+ ret, frame = cap.read()
75
+ if not ret:
76
+ break
77
+
78
+ frame = frame.astype(float) # uint8 -> float (uint8 型で frame**2 すると、overflow するため)
79
+ frame_sum += frame.sum(axis=-1) # 和を計算する。
80
+ frame_squared_sum += (frame ** 2).sum(axis=-1) # 自乗和を計算する。
81
+
82
+ mean = frame_sum / (num_frames * 3)
83
+ var = frame_squared_sum / (num_frames * 3) - mean ** 2
84
+ std = np.sqrt(var)
85
+
86
+ # ヒートマップで描画する。
87
+ fig, ax = plt.subplots()
88
+ ax.imshow(std)
89
+
90
+ plt.show()
91
+ ```