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

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

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

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

Python

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

Q&A

解決済

2回答

3874閲覧

pythonで画像を大量に開くとエラーが出る。

physics303

総合スコア89

OpenCV

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

Python

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

0グッド

0クリップ

投稿2018/09/13 02:37

編集2018/09/13 03:08

pathは読み込みたい画像のファイルパスがstrで入っているリストです。

python

1print(path[0]) 2print(len(path))

とすると、

TrainVal/VOCdevkit/VOC2011/JPEGImages/2007_001586.jpg
2223

と表示されます。ここで、

python

1 2img_sequence = [] 3 4for image in path: 5 img = Image.open(path) 6 img_sequence.append(img)

とすると、次のようなエラーがでます。

OSError: [Errno 24] Too many open files: 'TrainVal/VOCdevkit/VOC2011/JPEGImages/2009_001278.jpg'

そこで、ためしに、

python

1 2img_sequence = [] 3 4i = 0 5for image in path: 6 img = Image.open(path) 7 img_sequence.append(img) 8 print(i) 9 i = i + 1

とすると1020と表示された直後に、やはり

OSError: [Errno 24] Too many open files: 'TrainVal/VOCdevkit/VOC2011/JPEGImages/2009_001278.jpg'

というエラーが出ます。エラーの原因は何でしょうか。また、どうしたら解決できるでしょうか。

ちなみに

python

1 2img_sequence = [] 3 4i = 0 5for i in range(1020): 6 img = Image.open(path[i]) 7 img_sequence.append(img) 8 i = i + 1

とすればエラーは出ませんが、2223ファイルすべてをつなげた配列を作りたいのです。


追記

ここを参考に次のようにプログラムを変更させるとうまく行きました。(もっとスマートに書く方法があったら教えてください)

python

1 2img_sequence = [] 3 4for image in path: 5 fp = open(image,"rb") 6 img = Image.open(path) 7 img_sequence.append(img) 8 img.load() 9 fp.close()

これで、img_sequenceの各要素には画像が入りました。実際に

python

1img_sequence[1].show()

などとするとちゃんと画像が表示されます。

python

1print(len(img_sequence))

とすると2223と表示されます。一方で、

python

1images_original = np.asarray(images_original) 2print(images_original.shape)

と入力すると、
TypeError: int() argument must be a string, a bytes-like object or a number, not 'JpegImageFile'
というエラーが出るのは各画像ファイルの縦・横がバラバラだからでしょうか。

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

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

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

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

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

guest

回答2

0

ベストアンサー

Too many open files という OS エラー

並列処理で画像を読み込んでいるのでしょうか。
同時に開けるファイル数の上限に達したという OS エラーです。
Qiita の記事 などを参考にしてください。

OSError: [Errno 24] Too many open files

サンプルコード

下記のコードで1つの配列に concat できました。
画像サイズがバラバラなので、1つの配列にしたい場合は、ネットワークの入力サイズでリサイズしてください。

python

1import glob 2 3import cv2 4import numpy as np 5from PIL import Image 6 7img_files = glob.glob('/dataset/pascal_voc/VOCdevkit/VOC2012/JPEGImages/*.jpg') 8 9data = [] 10# 量が多いので最初の1000枚だけ読み込みました。 11for i, img_path in enumerate(img_files[:1000]): 12 print('{}/{} reading... {}'.format(i, len(img_files), img_path)) 13 img = np.array(Image.open(img_path)) # 画像を読み込む。 14 img = cv2.resize(img, (244, 244)) # リサイズする。 15 16 data.append(img) 17 18data = np.array(data) 19print(data.shape) # (1000, 244, 244, 3)

投稿2018/09/13 02:55

tiitoi

総合スコア21956

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

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

physics303

2018/09/13 03:14

ありがとうございます。リストにする分には各画像サイズがバラバラでも問題ないわけですが、配列にするとなると、画像サイズがそろってないとダメなわけですね。ありがとうございます。 私の目的はVOC2011のデータ・セットをFCNで学習する、という論文を実装することでした。任意入力画像サイズで学習させるためにはtrainファイルを配列として保持するのはよくないみたいですね。
tiitoi

2018/09/13 03:17

Fully Convolutional Network (FCN) の場合でも、学習時はリサイズで各画像サイズを揃えなないと、ミニバッチで流せません。バッチサイズ=1なら学習できないこともないですが、効率が非常に悪いので、基本的には学習時はリサイズしてミニバッチにします。 推論時は、1枚ずつであれば、任意サイズでかまいません。
physics303

2018/09/13 04:35

ご丁寧にありがとうございます。もうひとつ質問させてください。 tiitoiさんのスクリプトでは、 PILで読み込み→numpy配列に変換→resize となっていますが、PILではなく、cv2で読みこめば、numpy配列に変換する手間を省けるのではないでしょうか。(cv2.imreadで読み込んだ画像はnumpy配列になると記憶してます。) つまり、 cv2.imreadで読み込み→resize とするのがよりスマートではないでしょうか。これだと何か問題があるでしょうか。
tiitoi

2018/09/13 04:43

質問が PIL を使っていましたので、読み込みは PIL にしました。 もちろん、cv2.imread() でも問題ないです。 ただ1つ注意したいのは、PIL で画像を読み込んだ場合はチャンネルの並びは RGB となりますが、OpenCV で読み込んだ場合は BGR となります。 ネットワークの入力が RGB を期待されている場合は、読み込んだあとに cv2.cvtColor() で並び順を変更してください。
physics303
guest

0

Pythonはやっていないのでわかりませんが、
「Python "OSError: [Errno 24] Too many open files"」と検索すると
Python Subprocess: Too Many Open Filesがヒットしました。

そこから考えて、

可能性1: ファイルが多すぎる 解決法: ファイル数を減らす, または何回かに分ける
可能性2: ファイルパスの長さが長すぎる ( Windowsなら 260バイトらしいですが、これを上回って、500バイトとかね。 ) 解決法: ファイル名を短くする
可能性3: openしたのにcloseしていないため <= (最)有力候補? 解決法: appendした後の i = i + 1 の直前または直後のような次のステップに行く前までにcloseしておく

かなと。

最初は可能性1,2だと思ったけど、ヒットしたページでは「closeしていない~」とかってあるので、
たぶんcloseしていないことが原因かも。

実際の挙動から考えて、1020件ぐらいまでならメモリ不足(か何か)にならずにそのライブラリか言語かが処理可能だけど、1020+1 = 1021件目ぐらいからキャパオーバーでエラーを吐く...みたいなパターンじゃないかなと。

なので、次のステップ ( forの外側なり, 次のiの状態に... ) に行く前までにcloseしておく。

そうすれば多少はマシになると思います。


[追記1]

もっとスマートに...ですか。
うーん、仕様なので最終的には open -> 何らかの処理 -> close っていうのは必ずだと思いますが、
視覚的にわかりやすく...っていうのなら、関数化 ( メソッド化 ) するかクラス化するか。じゃないかなと。

例えば、C++ではデストラクタっていう、コンストラクタの反対の特殊なメソッドがあるので、

コンストラクタで openしておいて、デストラクタでclose。execメソッドとかみたいな独自のメソッドで何らかの処理...みたいにするクラスを定義してそれを使うとか。

で、検索してみるとPythonにもデストラクタは存在するみたいですが、「いつ起動するかわからん」らしく、あまり使われない様子。

根拠:Python基礎講座(13 クラス)

ということなのでこれは論外。

で、もうちょっと考えてみると、デザインパターンのTemplateMethodパターンが使えそう。

親クラスとして

openをしておくメソッド, closeをするメソッド, 実際の処理をするメソッド は 子クラスで定義するようにしておいて、execメソッドなるメソッドに流れを記述。そのクラスを継承してopenしておく...とかのメソッドを定義。
そうすれば execメソッドを呼び出せばいいだけ。

できれば純粋仮想とかがいいかもしれないけど、私はpythonはやっていないので詳しくない。なので普通のクラスとしてやると、

Python

1# あくまでイメージとして。 2class TestParent: 3 def open( filename ): 4 # ダミー 5 def close(): 6 # ダミー 7 def Main(): 8 # ダミー 9 def exec( filename ): 10 if open( filename ): 11 Main() 12 close() 13 14class TestChild(TestParent): 15 def open( filename ): 16 # ここでファイルを開く 17 def close(): 18 # ここでファイルを閉じる 19 def Main(): 20 # ここで実際に行いたい処理 ( 例えばファイルのデータを読み取って計算して返すとか ) 21 22# 呼び出し元にて 23file = TestChild() 24file.exec( ファイルパス ) # execメソッドを呼び出すだけ。

のような状態。

そうすれば質問で言えば

Python

1file = TestChild(); 2for image in path: 3 file.exec( image )

みたいな感じでできる。もちろん戻り値とかも必要だけど。

でも最終的にはcloseしたりするから対して変わらん ( 行数が長くなるが ) ので、スマートと言えるかどうかわかりませんが。

投稿2018/09/13 02:54

編集2018/09/13 06:02
BeatStar

総合スコア4958

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

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

physics303

2018/09/13 03:09

ありがとうございます。 追記に書いたように、次のステップに行く前にクローズさせたらうまくいきました。もっとスマートにコードを書く術があったら教えてください。よろしくおねがいします。
BeatStar

2018/09/13 05:35

もっとスマートに...ですか。 ちょっと回答本文の方に書きますね。
physics303

2018/09/13 06:12

ご丁寧にありがとうございました。勉強になります。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問