質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Matplotlib

MatplotlibはPythonのおよび、NumPy用のグラフ描画ライブラリです。多くの場合、IPythonと連携して使われます。

OpenCV

OpenCV(オープンソースコンピュータービジョン)は、1999年にインテルが開発・公開したオープンソースのコンピュータビジョン向けのクロスプラットフォームライブラリです。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

pandas

Pandasは、PythonでRにおけるデータフレームに似た型を持たせることができるライブラリです。 行列計算の負担が大幅に軽減されるため、Rで行っていた集計作業をPythonでも比較的簡単に行えます。 データ構造を変更したりデータ分析したりするときにも便利です。

Q&A

解決済

2回答

3337閲覧

計算時間が非常に長いのを改善したい

退会済みユーザー

退会済みユーザー

総合スコア0

Matplotlib

MatplotlibはPythonのおよび、NumPy用のグラフ描画ライブラリです。多くの場合、IPythonと連携して使われます。

OpenCV

OpenCV(オープンソースコンピュータービジョン)は、1999年にインテルが開発・公開したオープンソースのコンピュータビジョン向けのクロスプラットフォームライブラリです。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

pandas

Pandasは、PythonでRにおけるデータフレームに似た型を持たせることができるライブラリです。 行列計算の負担が大幅に軽減されるため、Rで行っていた集計作業をPythonでも比較的簡単に行えます。 データ構造を変更したりデータ分析したりするときにも便利です。

0グッド

0クリップ

投稿2019/07/26 09:28

ある表面の動画を20秒とって、その20秒の動画の標準偏差をpixel by pixelでplotする

python

1# -*- coding: utf-8 -*- 2import cv2 3import matplotlib.pyplot as plt 4from numpy import * 5import pandas as pd 6from scipy import signal 7 8video_path = "2cropcut.mkv" 9cap = cv2.VideoCapture(video_path) 10 11count = cap.get(cv2.CAP_PROP_FRAME_COUNT) 12fps = cap.get(cv2.CAP_PROP_FPS) 13 14width = cap.get(cv2.CAP_PROP_FRAME_WIDTH) 15height = cap.get(cv2.CAP_PROP_FRAME_HEIGHT) 16print(width) 17print(height) 18 19numS=raw_input("start frame: ") 20numS=int(numS) 21 22numE=raw_input("end frame: ") 23numE=int(numE) 24#numE=count 25print(numE) 26 27# 場所を決める 28#点滅の場所 29x1min=raw_input("点滅1左上のx座標:") 30y1min=raw_input("点滅1左上のy座標:") 31x1max=raw_input("点滅1右下のx座標:") 32y1max=raw_input("点滅1右下のy座標:") 33 34X1min=int(x1min) 35Y1min=int(y1min) 36X1max=int(x1max) 37Y1max=int(y1max) 38 39 40 41#ノイズの場所 42xnoisemin=raw_input("左上ノイズx座標:") 43ynoisemin=raw_input("左上ノイズy座標:") 44xnoisemax=raw_input("右下ノイズx座標:") 45ynoisemax=raw_input("右下ノイズy座標:") 46 47Xnoisemin=int(xnoisemin) 48Ynoisemin=int(ynoisemin) 49Xnoisemax=int(xnoisemax) 50Ynoisemax=int(ynoisemax) 51 52# フレーム [numS,numE] の範囲で各フレームの [ymin, ymax]x[xmin, xmax] の画素の平均を計算する。 53frame_no = arange(numS,numE) 54intensity1 = [] 55intensity2=[] 56intensity3=[] 57intensitynoise=[] 58sdMap=zeros((Y1max-Y1min,X1max-X1min)) # the standard deviation MAP 59totFrames=(Y1max-Y1min)*(X1max-X1min) 60import time as t 61XX=range(X1min,X1max) 62YY=range(Y1min,Y1max) 63print("XX:",XX) 64print("YY:",YY) 65for x in XX: 66 for y in YY: 67 print("x:%d y:%d"%(x,y)) 68 pixVal=[] # the pixel values for all frames! 69 t0=t.time() 70 for i in frame_no: 71 # フレーム frame_no を取得する。 72 cap.set(cv2.CAP_PROP_POS_FRAMES, i) 73 ret, frame = cap.read() #getFrame "i" 74 if not ret: 75 print('Failed to grab frame.') 76 break 77 pixVal=append(pixVal,frame[y,x]) 78 t1=t.time() # finish time 79 dt=t1-t0 # time in seconds 80 est=dt*totFrames # estimated time 81 sdMap[y,x]=pixVal.std() 82 print("filled x=%d y=%d sd=%4.2g Est: %d"%(x,y,pixVal.std(),est)) 83 84 85tPoints=arange(len(intensity1))*(1/fps) 86plt.grid(True) 87plt.xlim(X1min,X1max)#開始時間、終了時間の設定 88plt.ylim(Y1min,Y1max) 89plt.pcolor(sdMap,cmap="RdBu") 90plt.colorbar() 91plt.title("standard deviation Map") 92plt.show()

例えばフレーム数を5にしてこの5フレームの標準偏差をplotすると以下のようにplotされます
イメージ説明
5フレームで測定すると測定時間が30秒ほどかかりますが、20秒の動画(約900フレーム)を測定すると1日ほどかかります。また測定領域を広くしても読み込むピクセルが大きくなるので測定時間も大幅に大きくなります。
このような問題を改善するために何かよいコマンドなどは存在するのでしょうか?何か知っている方いらっしゃいましたら教えてください。よろしくお願いします

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

for x in XX: for y in YY: ...

Python でこのような for ループを書いてしまうと、かなり遅くなってしまうので、for 文は極力書かないようにしてください。
numpy を使うと、Vectorization により一度に計算できるため、基本的に for 文を書く必要はないはずです。

動画が数十秒の長さであれば、1GBぐらいメモリに空きがあれば、すべてメモリに展開することが可能ですので、先に動画の全フレームをすべて読みこんで (フレーム数, 高さ, 幅, 3) の numpy 配列を作成してから、numpy.std() 関数で一度に計算しましょう。

サンプルコード

python

1import cv2 2import matplotlib.pyplot as plt 3import numpy as np 4 5cap = cv2.VideoCapture("vtest.avi") 6 7# 先に全フレームを読み込む。 8frames = [] 9while True: 10 ret, frame = cap.read() 11 if not ret: 12 break 13 14 frames.append(frame) 15 16frames = np.array(frames) 17print(frames.shape) # (795, 576, 768, 3) 18 19size_mb = frames.nbytes / 1000000 20print(f"{size_mb:.2f} MB") # 1055.05 MB 21 22# 各ピクセルごとに全フレームの標準偏差を計算する。 23std = frames.std(axis=(0, 3)) 24 25# ヒートマップで描画する。 26fig, ax = plt.subplots() 27ax.imshow(std) 28 29plt.show()

イメージ説明

追記

800×800だとメモリーエラーとなります。

標準偏差を計算するのに必要なのは、各画素の和と自乗和だけなので、以下のようにすることでフレームの長さに関わらず、使用するメモリ量を固定できます。

標準偏差は分散の平方根なので、分散を以下の分散公式で求めればよいです。
式の導出はネット上に沢山情報があるので省略します。

分散の意味と求め方、分散公式の使い方

python

1import cv2 2import matplotlib.pyplot as plt 3import numpy as np 4 5cap = cv2.VideoCapture("vtest.avi") 6 7w = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) # フレームの幅 8h = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) # フレームの高さ 9num_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT)) # フレーム数 10 11frame_sum = np.zeros((h, w)) # 各画素の和を格納する配列 12frame_squared_sum = np.zeros((h, w)) # 各画素の平方和を格納する配列 13 14while True: 15 ret, frame = cap.read() 16 if not ret: 17 break 18 19 frame = frame.astype(float) # uint8 -> float (uint8 型で frame**2 すると、overflow するため) 20 frame_sum += frame.sum(axis=-1) # 和を計算する。 21 frame_squared_sum += (frame ** 2).sum(axis=-1) # 自乗和を計算する。 22 23mean = frame_sum / (num_frames * 3) 24var = frame_squared_sum / (num_frames * 3) - mean ** 2 25std = np.sqrt(var) 26 27# ヒートマップで描画する。 28fig, ax = plt.subplots() 29ax.imshow(std) 30 31plt.show()

追記

しかしながら出力画像を見てみると標準偏差ではないように思えます

追記した方法だと計算結果が違うというご指摘でしょうか?
一応、下記方法で最初に回答した方法 (方法1) と追記した方法 (方法2) で計算結果が一致することは確認しています。

python

1import cv2 2import numpy as np 3 4cap = cv2.VideoCapture("vtest.avi") 5 6# 方法1 7################################## 8frames = [] 9while True: 10 ret, frame = cap.read() 11 if not ret: 12 break 13 frames.append(frame) 14frames = np.array(frames) 15 16std1 = frames.std(axis=(0, 3)) 17 18# 方法2 19################################## 20cap = cv2.VideoCapture("vtest.avi") 21 22w = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) # フレームの幅 23h = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) # フレームの高さ 24num_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT)) # フレーム数 25 26frame_sum = np.zeros((h, w)) # 各画素の和を格納する配列 27frame_squared_sum = np.zeros((h, w)) # 各画素の平方和を格納する配列 28 29while True: 30 ret, frame = cap.read() 31 if not ret: 32 break 33 frame = frame.astype(float) # uint8 -> float (uint8 型で frame**2 すると、overflow するため) 34 frame_sum += frame.sum(axis=-1) # 和を計算する。 35 frame_squared_sum += (frame ** 2).sum(axis=-1) # 自乗和を計算する。 36 37mean = frame_sum / (num_frames * 3) 38var = frame_squared_sum / (num_frames * 3) - mean ** 2 39std2 = np.sqrt(var) 40 41################################## 42# 方法1 と 方法2 の計算結果が一致することを確認 43print(np.allclose(std1, std2)) # True

30秒の動画があってR+G+B/3が大きいところほど強度が高いです(赤です)
しかしながら全体的に強度の変化もないので標準偏差は小さくなるはずです(青になる)

python

1import matplotlib.pyplot as plt 2 3# ヒートマップで描画する。 4fig, ax = plt.subplots() 5img = ax.imshow(std) 6fig.colorbar(img) 7 8plt.show()

標準偏差が高い = 赤とは限らないです。色は matplotlib で可視化した際のカラーマップをどう設定したかによります。
例えば、質問の画像だと右側のカラーバーを見る限り、標準偏差が小さいと赤、大きいと青になっています。

投稿2019/07/26 09:55

編集2019/07/30 09:41
tiitoi

総合スコア21956

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2019/07/30 03:39

できました。ありがとうございます。確かに計算時間は格段に早くなりましたが、800×800だとメモリーエラーとなります。
tiitoi

2019/07/30 05:51

別解を追記しました。こちらの方法だとメモリエラーにならないかと思います。
退会済みユーザー

退会済みユーザー

2019/07/30 09:16

ありがとうございます。しかしながら出力画像を見てみると標準偏差ではないように思えます 30秒の動画があってR+G+B/3が大きいところほど強度が高いです(赤です) しかしながら全体的に強度の変化もないので標準偏差は小さくなるはずです(青になる)
tiitoi

2019/07/30 09:40

追記しましたが、matplotlib のカラーマップの問題ではないですか?質問のカラーマップだと値が小さいほど赤になります。
退会済みユーザー

退会済みユーザー

2019/07/30 09:55

すみません。勘違いしていました。解答ありがとうございました
guest

0

各画素のデータを計算する毎に動画からフレームを取り出しているように見えますが,それが遅い原因だったりしませんか?
(→例えば処理対象が5フレームならば動画からのフレームのキャプチャを5回だけで済ませば早くなったりしませんか?)

投稿2019/07/26 09:35

fana

総合スコア11654

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問