回答編集履歴

3

d

2019/07/30 09:41

投稿

tiitoi
tiitoi

スコア21956

test CHANGED
@@ -288,7 +288,9 @@
288
288
 
289
289
 
290
290
 
291
+ > 30秒の動画があってR+G+B/3が大きいところほど強度が高いです(赤です)
292
+
291
- >
293
+ > しかしながら全体的に強度の変化もないので標準偏差は小さくなるはずです(青になる)
292
294
 
293
295
 
294
296
 
@@ -314,12 +316,6 @@
314
316
 
315
317
 
316
318
 
317
- > 30秒の動画があってR+G+B/3が大きいところほど強度が高いです(赤です)
318
-
319
- > しかしながら全体的に強度の変化もないので標準偏差は小さくなるはずです(青になる)
320
-
321
-
322
-
323
319
  標準偏差が高い = 赤とは限らないです。色は matplotlib で可視化した際のカラーマップをどう設定したかによります。
324
320
 
325
321
  例えば、質問の画像だと右側のカラーバーを見る限り、標準偏差が小さいと赤、大きいと青になっています。

2

d

2019/07/30 09:41

投稿

tiitoi
tiitoi

スコア21956

test CHANGED
@@ -179,3 +179,147 @@
179
179
  plt.show()
180
180
 
181
181
  ```
182
+
183
+
184
+
185
+ ## 追記
186
+
187
+
188
+
189
+ > しかしながら出力画像を見てみると標準偏差ではないように思えます
190
+
191
+
192
+
193
+ 追記した方法だと計算結果が違うというご指摘でしょうか?
194
+
195
+ 一応、下記方法で最初に回答した方法 (方法1) と追記した方法 (方法2) で計算結果が一致することは確認しています。
196
+
197
+
198
+
199
+ ```python
200
+
201
+ import cv2
202
+
203
+ import numpy as np
204
+
205
+
206
+
207
+ cap = cv2.VideoCapture("vtest.avi")
208
+
209
+
210
+
211
+ # 方法1
212
+
213
+ ##################################
214
+
215
+ frames = []
216
+
217
+ while True:
218
+
219
+ ret, frame = cap.read()
220
+
221
+ if not ret:
222
+
223
+ break
224
+
225
+ frames.append(frame)
226
+
227
+ frames = np.array(frames)
228
+
229
+
230
+
231
+ std1 = frames.std(axis=(0, 3))
232
+
233
+
234
+
235
+ # 方法2
236
+
237
+ ##################################
238
+
239
+ cap = cv2.VideoCapture("vtest.avi")
240
+
241
+
242
+
243
+ w = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) # フレームの幅
244
+
245
+ h = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) # フレームの高さ
246
+
247
+ num_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT)) # フレーム数
248
+
249
+
250
+
251
+ frame_sum = np.zeros((h, w)) # 各画素の和を格納する配列
252
+
253
+ frame_squared_sum = np.zeros((h, w)) # 各画素の平方和を格納する配列
254
+
255
+
256
+
257
+ while True:
258
+
259
+ ret, frame = cap.read()
260
+
261
+ if not ret:
262
+
263
+ break
264
+
265
+ frame = frame.astype(float) # uint8 -> float (uint8 型で frame**2 すると、overflow するため)
266
+
267
+ frame_sum += frame.sum(axis=-1) # 和を計算する。
268
+
269
+ frame_squared_sum += (frame ** 2).sum(axis=-1) # 自乗和を計算する。
270
+
271
+
272
+
273
+ mean = frame_sum / (num_frames * 3)
274
+
275
+ var = frame_squared_sum / (num_frames * 3) - mean ** 2
276
+
277
+ std2 = np.sqrt(var)
278
+
279
+
280
+
281
+ ##################################
282
+
283
+ # 方法1 と 方法2 の計算結果が一致することを確認
284
+
285
+ print(np.allclose(std1, std2)) # True
286
+
287
+ ```
288
+
289
+
290
+
291
+ >
292
+
293
+
294
+
295
+ ```python
296
+
297
+ import matplotlib.pyplot as plt
298
+
299
+
300
+
301
+ # ヒートマップで描画する。
302
+
303
+ fig, ax = plt.subplots()
304
+
305
+ img = ax.imshow(std)
306
+
307
+ fig.colorbar(img)
308
+
309
+
310
+
311
+ plt.show()
312
+
313
+ ```
314
+
315
+
316
+
317
+ > 30秒の動画があってR+G+B/3が大きいところほど強度が高いです(赤です)
318
+
319
+ > しかしながら全体的に強度の変化もないので標準偏差は小さくなるはずです(青になる)
320
+
321
+
322
+
323
+ 標準偏差が高い = 赤とは限らないです。色は matplotlib で可視化した際のカラーマップをどう設定したかによります。
324
+
325
+ 例えば、質問の画像だと右側のカラーバーを見る限り、標準偏差が小さいと赤、大きいと青になっています。

1

d

2019/07/30 09:39

投稿

tiitoi
tiitoi

スコア21956

test CHANGED
@@ -89,3 +89,93 @@
89
89
 
90
90
 
91
91
  ![イメージ説明](ba452601b210881200219b9c0c385a97.png)
92
+
93
+
94
+
95
+ ## 追記
96
+
97
+
98
+
99
+ > 800×800だとメモリーエラーとなります。
100
+
101
+
102
+
103
+ 標準偏差を計算するのに必要なのは、各画素の和と自乗和だけなので、以下のようにすることでフレームの長さに関わらず、使用するメモリ量を固定できます。
104
+
105
+
106
+
107
+ 標準偏差は分散の平方根なので、分散を以下の分散公式で求めればよいです。
108
+
109
+ 式の導出はネット上に沢山情報があるので省略します。
110
+
111
+
112
+
113
+ [分散の意味と求め方、分散公式の使い方](https://sci-pursuit.com/math/statistics/variance.html)
114
+
115
+
116
+
117
+ ```python
118
+
119
+ import cv2
120
+
121
+ import matplotlib.pyplot as plt
122
+
123
+ import numpy as np
124
+
125
+
126
+
127
+ cap = cv2.VideoCapture("vtest.avi")
128
+
129
+
130
+
131
+ w = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) # フレームの幅
132
+
133
+ h = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) # フレームの高さ
134
+
135
+ num_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT)) # フレーム数
136
+
137
+
138
+
139
+ frame_sum = np.zeros((h, w)) # 各画素の和を格納する配列
140
+
141
+ frame_squared_sum = np.zeros((h, w)) # 各画素の平方和を格納する配列
142
+
143
+
144
+
145
+ while True:
146
+
147
+ ret, frame = cap.read()
148
+
149
+ if not ret:
150
+
151
+ break
152
+
153
+
154
+
155
+ frame = frame.astype(float) # uint8 -> float (uint8 型で frame**2 すると、overflow するため)
156
+
157
+ frame_sum += frame.sum(axis=-1) # 和を計算する。
158
+
159
+ frame_squared_sum += (frame ** 2).sum(axis=-1) # 自乗和を計算する。
160
+
161
+
162
+
163
+ mean = frame_sum / (num_frames * 3)
164
+
165
+ var = frame_squared_sum / (num_frames * 3) - mean ** 2
166
+
167
+ std = np.sqrt(var)
168
+
169
+
170
+
171
+ # ヒートマップで描画する。
172
+
173
+ fig, ax = plt.subplots()
174
+
175
+ ax.imshow(std)
176
+
177
+
178
+
179
+ plt.show()
180
+
181
+ ```