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

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

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

機械学習は、データからパターンを自動的に発見し、そこから知能的な判断を下すためのコンピューターアルゴリズムを指します。人工知能における課題のひとつです。

Python

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

Q&A

解決済

1回答

3045閲覧

OpenCVでの顔画像のトリミング・保存が失敗してしまう

sahuransan

総合スコア9

機械学習

機械学習は、データからパターンを自動的に発見し、そこから知能的な判断を下すためのコンピューターアルゴリズムを指します。人工知能における課題のひとつです。

Python

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

0グッド

0クリップ

投稿2018/08/29 15:11

前提・実現したいこと

画像の顔の部分をトリミングして保存するという事をしてみたくて、他の方が公開されていたコードを使ってみたのですがエラーが出てしまい実行できません。何がいけないのでしょうか?
初歩的な質問だったら申し訳ありませんが、是非レクチャーお願いいたします。

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

C:\Users\kiara\PycharmProjects\openCV\venv\Scripts\python.exe C:/Users/kiara/PycharmProjects/openCV/img_cuts.py Namespace(cascade='alt', input_dir='./input/', min=80, move_dir='/done/', neighbors=2, scale=1.3) Traceback (most recent call last): File "C:\Users\kiara\Anaconda3\lib\shutil.py", line 544, in move os.rename(src, real_dst) FileExistsError: [WinError 183] 既に存在するファイルを作成することはできません。: './input/00000001.jpg' -> './input//done/' During handling of the above exception, another exception occurred: Traceback (most recent call last): File "C:/Users/kiara/PycharmProjects/openCV/img_cuts.py", line 124, in <module> shutil.move(FLAGS.input_dir + file_name, FLAGS.input_dir + FLAGS.move_dir) File "C:\Users\kiara\Anaconda3\lib\shutil.py", line 558, in move copy_function(src, real_dst) File "C:\Users\kiara\Anaconda3\lib\shutil.py", line 257, in copy2 copyfile(src, dst, follow_symlinks=follow_symlinks) File "C:\Users\kiara\Anaconda3\lib\shutil.py", line 121, in copyfile with open(dst, 'wb') as fdst: OSError: [Errno 22] Invalid argument: './input//done/' Process finished with exit code 1

該当のソースコード

Python

1import cv2, os, argparse, shutil 2 3# 切り抜いた画像の保存先ディレクトリ 4SAVE_PATH = "./outputs/" 5 6# 基本的なモデルパラメータ 7FLAGS = None 8 9# 学習済モデルの種類 10CASCADE = ["default", "alt", "alt2", "tree", "profile", "nose"] 11 12# 直接実行されている場合に通る(importされて実行時は通らない) 13if __name__ == "__main__": 14 parser = argparse.ArgumentParser() 15 parser.add_argument( 16 "--cascade", 17 type=str, 18 default="alt", 19 choices=CASCADE, 20 help="cascade file." 21 ) 22 parser.add_argument( 23 "--scale", 24 type=float, 25 default=1.3, 26 help="scaleFactor value of detectMultiScale." 27 ) 28 parser.add_argument( 29 "--neighbors", 30 type=int, 31 default=2, 32 help="minNeighbors value of detectMultiScale." 33 ) 34 parser.add_argument( 35 "--min", 36 type=int, 37 default=80, 38 help="minSize value of detectMultiScale." 39 ) 40 parser.add_argument( 41 "--input_dir", 42 type=str, 43 default="./input/", 44 help="The path of input directory." 45 ) 46 parser.add_argument( 47 "--move_dir", 48 type=str, 49 default="/done/", 50 help="The path of moving detected files." 51 ) 52 53# パラメータ取得と実行 54FLAGS, unparsed = parser.parse_known_args() 55 56# 分類器ディレクトリ(以下から取得) 57# https://github.com/opencv/opencv/blob/master/data/haarcascades/ 58# https://github.com/opencv/opencv_contrib/blob/master/modules/face/data/cascades/ 59 60# 学習済モデルファイル 61if FLAGS.cascade == CASCADE[0]: # "default": 62 cascade_path = "C:/Users/kiara/Desktop/opencv-master/data/haarcascades/haarcascade_frontalface_default.xml" 63elif FLAGS.cascade == CASCADE[1]: # "alt": 64 cascade_path = "C:/Users/kiara/Desktop/opencv-master/data/haarcascades/haarcascade_frontalface_alt.xml" 65elif FLAGS.cascade == CASCADE[2]: # "alt2": 66 cascade_path = "C:/Users/kiara/Desktop/opencv-master/data/haarcascades/haarcascade_frontalface_alt2.xml" 67elif FLAGS.cascade == CASCADE[3]: # "tree": 68 cascade_path = "C:/Users/kiara/Desktop/opencv-master/data/haarcascades/haarcascade_frontalface_alt_tree.xml" 69elif FLAGS.cascade == CASCADE[4]: # "profile": 70 cascade_path = "C:/Users/kiara/Desktop/opencv-master/data/haarcascades/haarcascade_profileface.xml" 71elif FLAGS.cascade == CASCADE[5]: # "nose": 72 cascade_path = "C:/Users/kiara/Desktop/opencv_contrib-master/modules/face/data/cascades/haarcascade_mcs_nose.xml" 73 74# カスケード分類器の特徴量を取得する 75faceCascade = cv2.CascadeClassifier(cascade_path) 76 77# 顔検知に成功した数(デフォルトで0を指定) 78face_detect_count = 0 79 80# 顔検知に失敗した数(デフォルトで0を指定) 81face_undetected_count = 0 82 83# フォルダ内ファイルを変数に格納(ディレクトリも格納) 84files = os.listdir(FLAGS.input_dir) 85 86# 成功ファイルを移動いない場合は、出力用のディレクトリが存在する場合、削除して再作成 87if FLAGS.move_dir == "": 88 if os.path.exists(SAVE_PATH): 89 shutil.rmtree(SAVE_PATH) 90 os.mkdir(SAVE_PATH) 91 92print(FLAGS) 93 94# 集めた画像データから顔が検知されたら、切り取り、保存する。 95for file_name in files: 96 97 # ファイルの場合(ディレクトリではない場合) 98 if os.path.isfile(FLAGS.input_dir + file_name): 99 100 # 画像ファイル読込 101 img = cv2.imread(FLAGS.input_dir + file_name) 102 103 # 大量に画像があると稀に失敗するファイルがあるのでログ出力してスキップ(原因不明) 104 if img is None: 105 print(file_name + ':Cannot read image file') 106 continue 107 108 # カラーからグレースケールへ変換(カラーで顔検出しないため) 109 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) 110 111 # 顔検出 112 face = faceCascade.detectMultiScale(gray, scaleFactor=FLAGS.scale, minNeighbors=FLAGS.neighbors, 113 minSize=(FLAGS.min, FLAGS.min)) 114 115 if len(face) > 0: 116 for rect in face: 117 # 切り取った画像出力 118 cv2.imwrite(SAVE_PATH + str(face_detect_count) + file_name, 119 img[rect[1]:rect[1] + rect[3], rect[0]:rect[0] + rect[2]]) 120 face_detect_count = face_detect_count + 1 121 122 # 検出できたファイルは移動 123 if FLAGS.move_dir != "": 124 shutil.move(FLAGS.input_dir + file_name, FLAGS.input_dir + FLAGS.move_dir) 125 else: 126 print(file_name + ':No Face') 127 face_undetected_count = face_undetected_count + 1 128 129print('Undetected Image Files:%d' % face_undetected_count) 130

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

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

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

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

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

guest

回答1

0

ベストアンサー

既に存在するファイルを作成することはできません。

原因は移動先にinput/done/00000001.jpgのファイルが存在するのが問題です。
※)どうしてこの事象が発生するのかは後述します。

対策としてはPath#replaceを使えばよいかと。
以下は未テストコードです。

Python

1from pathlib import Path 2 3# 前略 4 5# 成功ファイルを移動いない場合は、出力用のディレクトリが存在する場合、削除して再作成 6if FLAGS.move_dir == "": 7 if os.path.exists(SAVE_PATH): 8 shutil.rmtree(SAVE_PATH) 9 os.mkdir(SAVE_PATH) 10else: # この行を追加 11 move_dir = Path(FLAGS.input_dir, FLAGS.move_dir) 12 # input/done ディレクトリの作成 13 move_dir.mkdir(parents=True, exist_ok=True) 14 15# 中略 16 17# 集めた画像データから顔が検知されたら、切り取り、保存する。 18for file_name in files: 19 src_file = Path(FLAGS.input_dir, file_name) 20 # ファイルの場合(ディレクトリではない場合) 21 if src_file.is_file(): 22 # 画像ファイル読込 23 img = cv2.imread(str(src_file)) 24 25 # 中略 26 27 # 検出できたファイルは移動 28 if FLAGS.move_dir != "": 29 src_file.replace(move_dir / file_name)

※解説
Windowsではshutil.move()が内部で呼び出しているos.rename()がリネーム先ファイルが存在する時にOSErrorになる点が他のOS(macOS/Linux)と動作が違います。

File "C:\Users\kiara\Anaconda3\lib\shutil.py", line 544, in move
os.rename(src, real_dst)

憶測ですが、サンプルコード記載した人はMacOSlinuxで動作テストを行い、質問者さんはWindowsで動作させたことでこの事象が発生したのではないかと。
Python言語においてクロスプラットフォーム環境でrename処理を行うにはos.replaceもしくはPath#replaceを使ってくださいな。

◆参考情報

Unixでは、dst が存在し、かつファイルの場合、ユーザーの権限があるかぎり**暗黙のうちに置き換えられます。**この操作は、一部の Unix 系システムにおいて src と dst が異なるファイルシステム上にあると失敗することがあります。ファイル名の変更が成功する場合はアトミック操作となります (これは POSIX 要求仕様です)。Windows では、dst がすでに存在する場合には、たとえファイルの場合でも OSError が送出されます。

投稿2018/08/29 18:36

編集2018/09/02 08:37
umyu

総合スコア5846

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

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

sahuransan

2018/09/02 08:12

詳しくとても丁寧な説明、ありがとうございました。OSの問題だとは考えもしていなかったので大変参考になりました。 テストコードを参考にして書き換えてみた所、今度は以下のようなエラー文が出たのですがこれはどういった意味でしょう?無知で申し訳ありません。 Traceback (most recent call last): File "C:/Users/kiara/PycharmProjects/openCV/img_cuts.py", line 134, in <module> src_file.replace(move_dir / file_name) NameError: name 'move_dir' is not defined
umyu

2018/09/02 08:17

@sahuransanさんへ NameError: name 'move_dir' is not definedという変数が定義されていないというエラーです。 参考コードの上の方にmove_dir = Path(FLAGS.input_dir, FLAGS.move_dir)と書いてあるので、そちらも記載してくださいな。
sahuransan

2018/09/02 08:32 編集

記述の間違いはなくなっているとは思うのですが、何故か同じエラーが出てしまいます。以下、どこか間違っていますでしょうか? # 成功ファイルを移動いない場合は、出力用のディレクトリが存在する場合、削除して再作成 if FLAGS.move_dir == "": if os.path.exists(SAVE_PATH): shutil.rmtree(SAVE_PATH) os.mkdir(SAVE_PATH) move_dir = Path(FLAGS.input_dir, FLAGS.move_dir) # input/done ディレクトリの作成 move_dir.mkdir(parents=True, exist_ok=True) print(FLAGS) # 集めた画像データから顔が検知されたら、切り取り、保存する。 for file_name in files: src_file = Path(FLAGS.input_dir, file_name) # ファイルの場合(ディレクトリではない場合) if src_file.is_file(): # 画像ファイル読込 img = cv2.imread(str(src_file)) # 大量に画像があると稀に失敗するファイルがあるのでログ出力してスキップ(原因不明) if img is None: print(file_name + ':Cannot read image file') continue # カラーからグレースケールへ変換(カラーで顔検出しないため) gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 顔検出 face = faceCascade.detectMultiScale(gray, scaleFactor=FLAGS.scale, minNeighbors=FLAGS.neighbors, minSize=(FLAGS.min, FLAGS.min)) if len(face) > 0: for rect in face: # 切り取った画像出力 cv2.imwrite(SAVE_PATH + str(face_detect_count) + file_name, img[rect[1]:rect[1] + rect[3], rect[0]:rect[0] + rect[2]]) face_detect_count = face_detect_count + 1 # 検出できたファイルは移動 if FLAGS.move_dir != "": src_file.replace(move_dir / file_name) else: print(file_name + ':No Face') face_undetected_count = face_undetected_count + 1 すいませんコピペしたらインデントがめちゃくちゃになってしまいました...
umyu

2018/09/02 08:38 編集

あ、ごめんなさい。回答コードがミスしてました。回答コードを修正しました。
sahuransan

2018/09/02 09:27

ありがとうございます!!完璧に動きました! 本当に助かりましたm(_ _"m)
umyu

2018/09/02 09:56

@sahuransanさんへ 問題が解決してよかったですー。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問