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

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

新規登録して質問してみよう
ただいま回答率
85.50%
Python 3.x

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

Python

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

Q&A

解決済

3回答

9819閲覧

画像処理→ファイル処理の速度を向上させたい

p_pp

総合スコア17

Python 3.x

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

Python

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

0グッド

1クリップ

投稿2018/08/22 20:35

編集2018/08/23 14:50

前提・実現したいこと

画像処理について独学で学んでいるのですが

動画をコマ割り・二値化 → 黒の領域が大きい写真を探す → 見つかった画像より前の画像を削除 → 最大画像を0として番号を振りなおす 

という処理を行いたいと考えています。

発生している問題・エラーメッセージ

調べながら何とか完成させたのですがプログラムが悪いのか
処理に時間がかかりすぎます
大体5000ファイル処理したいのですが10分ほどかかってしまいます

該当のソースコード

python

1import os 2import cv2 3import numpy as np 4import glob 5from PIL import Image 6import os 7 8 9file_list = glob.glob('//image_dir//*jpg') 10 11for file in file_list: 12 os.remove(file) 13 14 15#動画コマワリ 16movie_name='s' 17movie='//directory//1_.avi' 18 19cap=cv2.VideoCapture(movie) 20count=0 21while True: 22 ret,frame=cap.read() 23 if ret==True: 24 count += 1 25 cv2.imwrite('//image_dir//' + movie_name+'_' + str("{0:05d}".format(count)) + '.jpg',frame) 26 else: 27 break 28 29#最大画像を取得 30for j in range(1,5000): 31 filename='//image_dir//s_%05d.jpg'%(j) 32 im = np.array(Image.open(filename).convert('L')) 33 34#閾値 35 im_ = (im > 180) * 255 36 c=0 37#最大画像を探索 38 max1=0 39 for i in range(2048): 40 if im_[1,i]==0: 41 c=c+1 42 if max1<c: 43 max1=c 44 d=j 45 c=0 46print(d) 47 48#不要画像の削除 49for l in range(1,d): 50 os.remove('//image_dir//s_%05d.jpg'%(l)) 51 52a=0 53directory='//image_dir//' 54files=os.listdir(directory) 55for file in files: 56 path = os.path.join(directory,file) #パス 57 name = str('%06d')%(a)+'.jpg' 58 target = os.path.join(directory,name) 59 os.rename(path,target) 60 a = a + 1

コマ割で時間がかかってしまうのは分かるのですが、もう少し短縮したいです。

ご教授お願い致します。

追記

import os import cv2 import numpy as np import glob from PIL import Image import os import sys import re file_list = glob.glob('//image_dir//*jpg') for file in file_list: os.remove(file) #動画コマワリ movie_name='s' movie='//11.avi' cap=cv2.VideoCapture(movie) count=0 max1=0 c=0 while True: ret,frame=cap.read() if ret==True: cv2.imwrite('//image_dir//' + movie_name+'_' + str("{0:05d}".format(count)) + '.jpg',frame) #二値化 filename='//image_dir//s_%05d.jpg'%(count) im = np.array(Image.open(filename).convert('L')) im_ = (im > 180) * 255 #最大画像を探索 for i in range(2048): if im_[100,i]==0: c=c+1 if max1<c: max1=c c=0 pil_img = Image.fromarray(im) pil_img.save('//image_dir//s_00000.jpg') count=1 else: count += 1 else: break

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

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

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

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

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

guest

回答3

0

回答ではないですが、追記・修正依頼に長文では書けないので。

◆速度向上させる時の原則
0. 要件を満たしているコードを最適化する。
ret,frame=cap.read()で動画のフレームを読んでcv2.imwriteしていますが、5000フレーム以上cv2.imwriteしていませんか?

  1. テストコードを書く

速度向上はコード変更を伴うので、既存の動作と同じようになるように簡単なテストコードを書いてください。
これによってコード変更によるコード破壊が防げます。

  1. 最適化後の目標タイムを決める。

現状 5000ファイルが10分との事ですが。
1秒でも改善されたら良い以外だと最終的な目標タイムを決めないと、ぐだぐだになりやすいです。
※パソコンのハード上の制約上、この速度以上は無理が原理上発生するので

  1. 推測せずにまずプロファイラを取る

CPUプロファイラ、メモリプロファイラを取りボトルネックポイントを確認してくださいな。
コードを関数化しないと取りづらいので、処理ごとに関数化されることをお勧めします。

あとIO操作を伴うならpathlibモジュールが便利です。

投稿2018/08/22 22:47

編集2018/08/22 22:49
umyu

総合スコア5846

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

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

p_pp

2018/08/23 07:18

ご指摘ありがとうございます さっそくプロファイルとってみます!!
guest

0

ベストアンサー

読み込んだ時点で
「動画をコマ割り・二値化」
までやって、
「黒の領域が大きい写真」
が更新されるたびに逐次上書きしてしまえば、一度すべて画像を書き出した後に、いらないものを消す必要がなくなります。

投稿2018/08/22 22:22

mkgrei

総合スコア8560

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

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

p_pp

2018/08/23 07:15

import os import cv2 import numpy as np import glob from PIL import Image import os import sys import re file_list = glob.glob('//image_dir//*jpg') for file in file_list: os.remove(file) #動画コマワリ movie_name='s' movie='//11.avi' cap=cv2.VideoCapture(movie) count=0 max1=0 c=0 while True: ret,frame=cap.read() if ret==True: cv2.imwrite('//image_dir//' + movie_name+'_' + str("{0:05d}".format(count)) + '.jpg',frame) #二値化 filename='//image_dir//s_%05d.jpg'%(count) im = np.array(Image.open(filename).convert('L')) im_ = (im > 180) * 255 #最大画像を探索 for i in range(2048): if im_[100,i]==0: c=c+1 if max1<c: max1=c c=0 pil_img = Image.fromarray(im) pil_img.save('//image_dir//s_00000.jpg') count=1 else: count += 1 else: break
p_pp

2018/08/23 07:17

ありがとうございます トライしてみましたが最大画像に更新されません プログラムが間違っているのでしょうか
mkgrei

2018/08/23 09:18

インデントが崩れていてif文の範囲がわからないのでなんとも言えません。 質問文に追記して、インデントを有効にしてください。
p_pp

2018/08/23 14:51

よろしくお願い致します.
p_pp

2018/08/23 19:51

すみません 解決しました。 c=0の位置が違いました。。
guest

0

あまり詳しく検討してはいませんが、思いつくことを。

  • ファイル読み込み/書き込みを多用していますが、おそらく最大のボトルネックになっています。部分的にでもメモリに載せて処理できませんか? あとはasyncio等で隠蔽するか(難しいですが)
  • 探索のコードは疑問。画像の配列の1行目に存在する0の数が大きければという処理ですか? max1=0がループの内側にあるのもおかしい気がします。
  • 本題と関係ありませんが、スペース1つ単位のインデントはさすがにちょっと・・・

投稿2018/08/22 22:02

hayataka2049

総合スコア30933

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

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

p_pp

2018/08/23 07:19

そのとおりでした max1の位置が間違っていました ありがとうございます スペースひとつ単位のインデントはやめたほうがいいのでしょうか
hayataka2049

2018/08/23 16:26

見やすいことが大切なので、視認性を考えるとスペース1つはやめたほうが良いですね。 ちなみに公式コーディング規約のPEP8ではスペース4つを推奨しています。 https://pep8-ja.readthedocs.io/ja/latest/
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問