diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..eddf46e --- /dev/null +++ b/.gitignore @@ -0,0 +1,175 @@ +### Python ### +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/#use-with-ide +.pdm.toml + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ + +### Python Patch ### +# Poetry local configuration file - https://python-poetry.org/docs/configuration/#local-configuration +poetry.toml + +# ruff +.ruff_cache/ + +# LSP config files +pyrightconfig.json + +images-fix/ +data/ +data.zip \ No newline at end of file diff --git a/auto-fix.py b/auto-fix.py new file mode 100644 index 0000000..6493df4 --- /dev/null +++ b/auto-fix.py @@ -0,0 +1,117 @@ +import os +import cv2 +import pandas as pd +import re + +class ImageProcessor: + def __init__(self): + self.output_dir = "images-fix" + os.makedirs(self.output_dir, exist_ok=True) + # pos番号の変換マップを定義 + self.pos_map = { + '3': '4', + '4': '3', + '7': '8', + '8': '7' + } + + def get_new_filename(self, original_filename): + """ファイル名のpos番号を必要に応じて変更する""" + pattern = r'(.*pos)(\d+)(.*)' + match = re.match(pattern, original_filename) + if match: + pos_num = match.group(2) + if pos_num in self.pos_map: + return re.sub(pattern, f'\\g<1>{self.pos_map[pos_num]}\\g<3>', original_filename) + return original_filename + + def check_duplicate_filename(self, filename): + """出力ディレクトリで重複をチェック""" + return os.path.exists(os.path.join(self.output_dir, filename)) + + def process_folder(self, folder_path): + results_csv = os.path.join(folder_path, "results.csv") + images_folder = os.path.join(folder_path, "images") + + if not os.path.exists(results_csv): + print(f"結果ファイルが見つかりません: {results_csv}") + return + + df = pd.read_csv(results_csv) + + for _, row in df.iterrows(): + image_file_name = row["image_file_name"] + image_path = os.path.join(images_folder, image_file_name) + + if not os.path.exists(image_path): + print(f"画像ファイルが見つかりません: {image_path}") + continue + + image = cv2.imread(image_path) + if image is None: + print(f"画像の読み込みに失敗しました: {image_path}") + continue + + # 新しいファイル名を取得 + new_filename = self.get_new_filename(image_file_name) + output_path = os.path.join(self.output_dir, new_filename) + + # ファイルを保存 + cv2.imwrite(output_path, image) + print(f"保存完了: {output_path}") + +def get_numeric_folders(base_dir="data"): + """ + dataディレクトリ���の数字名フォルダを取得する + """ + folders = [] + if os.path.exists(base_dir): + for item in os.listdir(base_dir): + if os.path.isdir(os.path.join(base_dir, item)) and item.isdigit(): + folders.append(item) + return sorted(folders, key=lambda x: int(x)) + +def main(): + processor = ImageProcessor() + + # dataディレクトリ内の数字フォルダを取得 + numeric_folders = get_numeric_folders() + if not numeric_folders: + print("処理対象のフォルダが見つかりません") + return + + print("処理するフォルダを選択してください:") + for i, folder in enumerate(numeric_folders, 1): + print(f"{i}: {folder}") + print("0: 全てのフォルダを処理") + + while True: + try: + choice = input("番号を入力してください: ").strip() + if not choice: + continue + + choice = int(choice) + if choice == 0: + # 全てのフォルダを処理 + folders_to_process = numeric_folders + break + elif 1 <= choice <= len(numeric_folders): + # 選択されたフォルダのみ処理 + folders_to_process = [numeric_folders[choice-1]] + break + else: + print(f"1から{len(numeric_folders)}までの数字、または0を入力してください") + except ValueError: + print("有効な数字を入力してください") + + # 選択されたフォルダを処理 + for folder in folders_to_process: + folder_path = os.path.join("data", folder.zfill(2)) + print(f"\n=== フォルダ {folder} の処理を開始 ===") + processor.process_folder(folder_path) + + print("\n処理が完了しました") + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/main.py b/main.py new file mode 100644 index 0000000..b8092f4 --- /dev/null +++ b/main.py @@ -0,0 +1,208 @@ +import os +import cv2 +import pandas as pd +import re + +class ImageProcessor: + def __init__(self): + self.output_dir = "images-fix" + os.makedirs(self.output_dir, exist_ok=True) + + def get_new_filename(self, original_filename, new_pos_number): + """ファイル名のpos番号を変更する""" + pattern = r'(.*pos)(\d+)(.*)' + return re.sub(pattern, f'\\g<1>{new_pos_number}\\g<3>', original_filename) + + def check_duplicate_filename(self, filename): + """出力ディレクトリで重複をチェック""" + return os.path.exists(os.path.join(self.output_dir, filename)) + + def process_folder(self, folder_path): + results_csv = os.path.join(folder_path, "results.csv") + images_folder = os.path.join(folder_path, "images") + + if not os.path.exists(results_csv): + print(f"結果ファイルが見つかりません: {results_csv}") + return + + df = pd.read_csv(results_csv) + + for _, row in df.iterrows(): + image_file_name = row["image_file_name"] + image_path = os.path.join(images_folder, image_file_name) + + if not os.path.exists(image_path): + print(f"画像ファイルが見つかりません: {image_path}") + continue + + image = cv2.imread(image_path) + if image is None: + print(f"画像の読み込みに失敗しました: {image_path}") + continue + + # 画像を表示 + cv2.imshow('Image', image) + print(f"現在の画像: {image_file_name}") + print("Enterキーを押して保存、または新しいpos番号を入力してください(1-99):") + + input_buffer = "" + while True: + key = cv2.waitKey(0) & 0xFF + + if key == 13: # Enterキー + if input_buffer: # 数字が入力されている場合 + new_pos_number = input_buffer + new_filename = self.get_new_filename(image_file_name, new_pos_number) + + while True: + output_path = os.path.join(self.output_dir, new_filename) + + if self.check_duplicate_filename(new_filename): + print("\nファイルが重複しています。選択してください:") + print("1: 新しいファイル名を入力する") + print("2: スキップする") + + choice = input("選択 (1/2): ").strip() + if choice == "1": + print(f"\n現在のファイル名: {new_filename}") + new_name = input("新しいファイル名を入力してください: ").strip() + + if not new_name: + print("入力がキャンセルされました") + break + + if not new_name.endswith(os.path.splitext(image_file_name)[1]): + new_name += os.path.splitext(image_file_name)[1] + + new_filename = new_name + continue + + elif choice == "2": + print("スキップします") + break + + else: + print("無効な選択です。1か2を入力してください。") + continue + + cv2.imwrite(output_path, image) + print(f"保存完了: {output_path}") + break + break + + else: # 直接Enterが押された場合 + output_path = os.path.join(self.output_dir, image_file_name) + if self.check_duplicate_filename(image_file_name): + print("\nファイルが重複しています。選択してください:") + print("1: 新しいファイル名を入力する") + print("2: スキップする") + + while True: + choice = input("選択 (1/2): ").strip() + if choice == "1": + while True: + print(f"\n現在のファイル名: {image_file_name}") + new_name = input("新しいファイル名を入力してください: ").strip() + + # 入力が空の場合はスキップ + if not new_name: + print("入力がキャンセルされました") + break + + # 拡張子の確認と追加 + if not new_name.endswith(os.path.splitext(image_file_name)[1]): + new_name += os.path.splitext(image_file_name)[1] + + output_path = os.path.join(self.output_dir, new_name) + + # 新しいファイル名でも重複チェック + if self.check_duplicate_filename(new_name): + print("Warning: 指定されたファイル名も既に存在します。") + continue + + # 問題なければ保存して終了 + cv2.imwrite(output_path, image) + print(f"保存完了: {output_path}") + break + break + + elif choice == "2": + print("スキップします") + break + + else: + print("無効な選択です。1か2を入力してください。") + continue + cv2.imwrite(output_path, image) + print(f"保存完了: {output_path}") + break + + elif key >= ord('0') and key <= ord('9'): + input_buffer += chr(key) + print(f"入力中: {input_buffer}") + + elif key == 8: # バックスペース + input_buffer = input_buffer[:-1] + print(f"入力中: {input_buffer}") + + elif key == 27: # ESCキー + print("処理をスキップします") + break + + cv2.destroyWindow('Image') + +def get_numeric_folders(base_dir="data"): + """ + dataディレクトリ内の数字名フォルダを取得する + """ + folders = [] + if os.path.exists(base_dir): + for item in os.listdir(base_dir): + if os.path.isdir(os.path.join(base_dir, item)) and item.isdigit(): + folders.append(item) + return sorted(folders, key=lambda x: int(x)) + +def main(): + processor = ImageProcessor() + + # dataディレクトリ内の数字フォルダを取得 + numeric_folders = get_numeric_folders() + if not numeric_folders: + print("処理対象のフォルダが見つかりません") + return + + print("処理するフォルダを選択してください:") + for i, folder in enumerate(numeric_folders, 1): + print(f"{i}: {folder}") + print("0: 全てのフォルダを処理") + + while True: + try: + choice = input("番号を入力してください: ").strip() + if not choice: + continue + + choice = int(choice) + if choice == 0: + # 全てのフォルダを処理 + folders_to_process = numeric_folders + break + elif 1 <= choice <= len(numeric_folders): + # 選択されたフォルダのみ処理 + folders_to_process = [numeric_folders[choice-1]] + break + else: + print(f"1から{len(numeric_folders)}までの数字、または0を入力してください") + except ValueError: + print("有効な数字を入力してください") + + # 選択されたフォルダを処理 + for folder in folders_to_process: + folder_path = os.path.join("data", folder.zfill(2)) + print(f"\n=== フォルダ {folder} の処理を開始 ===") + processor.process_folder(folder_path) + + print("\n処理が完了しました") + +if __name__ == "__main__": + main() \ No newline at end of file