当前位置:首页 > Python > 正文内容

Smart Image Organizer Assistant 图片数据集重命名、清理,去重错误文件 Python实现

chanra1n4个月前 (05-01)Python949

功能主要围绕处理目录中的图片文件:识别、检查、删除非图片文件以及重命名操作。这个程序是一个很好的例子,展示了如何使用Python的os库和Pillow(PIL的升级版本)库来执行文件系统的操作。
首先,介绍一下Python的os库。这个库提供了一系列的功能,用来与操作系统进行交互,比如文件的创建、删除、遍历目录等操作。而Pillow库是Python中一个非常强大的处理图片的库,它支持打开、修改、保存多种格式的图片文件。

1. 批量获取子文件夹

我们的第一个函数 get_subfolders 的工作是获取给定根目录下的所有子文件夹路径。程序通过列表推导式,结合os.listdir() 和 os.path.join() 方法来完成这项工作。这个函数可以帮助我们完成初步的目录结构解析。

2. 删除非图片文件

delete_non_image_files 函数通过遍历给定子目录下的所有文件,并检查文件的扩展名是否属于指定的图片格式集合,如果不是,则使用 os.remove() 方法将它们删除。它使用了Python集合,这是一个高效的数据结构,用于检查元素是否存在于集合中。

3. 检查并记录问题图片

check_pic 函数尝试打开一个图片文件,如果文件不存在、有问题或者是一个"解压缩炸弹",它们会引发异常。在这种情况下,该函数会将问题文件的路径记录到一个文本文件中,并尝试删除这个图片文件。这个功能提高了数据清洗的效率。

4. 图片文件重命名

重命名部分是通过 rename_image_files_in_subfolder 函数来完成的。它首先会遍历给定子目录下的所有文件,并为图片文件生成新的文件名,新文件名包括子文件夹的名称和一个独一无二的索引。在重命名之前,它会调用 check_pic 来确保图片文件没有问题。如果需要,它也会相应地处理文件名冲突。

5. 递归处理所有文件夹

最后,我们有 rename_image_files_in_subfolders 函数,它递归地处理给定路径下的所有文件夹,对每个子文件夹调用 rename_image_files_in_subfolder 方法。
我想强调一下最后的测试部分。当程序作为主模块运行时,会进行实际的操作,删除所有子文件夹中的非图片文件,并递归地重命名所有的图片文件。这确保了脚本在执行时不会有未预期的行为。


程序源码:

import os
from PIL import Image

# 获取指定目录下的所有子文件夹
def get_subfolders(path):
    subfolders = [os.path.join(path, o) for o in os.listdir(path)
                  if os.path.isdir(os.path.join(path, o))]
    return subfolders

# 删除指定目录下的所有子文件夹中不是图片文件的文件
def delete_non_image_files(subfolder):
    allowed_exts = {'.jpg', '.jpeg', '.png', '.bmp', '.jpe'}
    for file_name in os.listdir(subfolder):
        file_path = os.path.join(subfolder, file_name)
        if os.path.isfile(file_path):
            file_ext = os.path.splitext(file_name)[1].lower()
            if file_ext not in allowed_exts:
                os.remove(file_path)  # 如果不是图片格式,就删除这个文件

# 检查图片是否有问题并记录问题图片
def check_pic(path_pic, files_to_delete):
    try:
        img = Image.open(path_pic, 'r')
        img.load()
        return True
    except (FileNotFoundError, OSError, Image.DecompressionBombError):
        f = open('False.txt', 'a+')
        f.write(str(path_pic) + '\n')
        f.close()
        try:
            os.remove(path_pic)
        except PermissionError:
            print('File In Use:'+path_pic)
            files_to_delete.append(path_pic)
        except (FileNotFoundError, OSError) as e:
            print(f"删除文件 {path_pic} 失败: {e}")
        return False

# 重命名指定目录下的所有子文件夹中的图片文件
def rename_image_files_in_subfolder(subfolder, subfolder_name):
    try:
        unique_index = 0
        files_to_delete = []  # 保存需要删除的文件
        for index, file_name in enumerate(os.listdir(subfolder)):
            file_path = os.path.join(subfolder, file_name)
            if os.path.isfile(file_path):
                file_ext = os.path.splitext(file_name)[1].lower()
                if file_ext in ['.jpg', '.jpeg', '.png', '.bmp', '.jpe']:
                    # 在重命名之前检查图片是否有问题
                    if check_pic(file_path, files_to_delete):
                        # 如果图片没问题,进行重命名
                        new_file_name = f"{subfolder_name}_{index+1}{file_ext}"
                        new_file_path = os.path.join(subfolder, new_file_name)
                        while os.path.exists(new_file_path):
                            unique_index += 1
                            new_file_name = f"{subfolder_name}_{index+1}_{unique_index}{file_ext}"
                            new_file_path = os.path.join(subfolder, new_file_name)
                        os.rename(file_path, new_file_path)
    except PermissionError:
        print(f"Error: failed to rename files in subfolder {subfolder}.")

# 递归处理所有文件夹
def rename_image_files_in_subfolders(path):
    for root, dirs, files in os.walk(path):
        for subfolder in dirs:
            subfolder_path = os.path.join(root, subfolder)
            rename_image_files_in_subfolder(subfolder_path, subfolder)

# 测试
if __name__ == '__main__':
    for root, dirs, files in os.walk("."):
        for subfolder in dirs:
            subfolder_path = os.path.join(root, subfolder)
            delete_non_image_files(subfolder_path)
            rename_image_files_in_subfolders(subfolder_path)

新版本:

import os
from PIL import Image, ImageFile

# 允许加载截断的图像文件
ImageFile.LOAD_TRUNCATED_IMAGES = True

# 定义允许的图片文件扩展名
ALLOWED_EXTS = {'.jpg', '.jpeg', '.png', '.bmp', '.jpe'}
MIN_DIMENSION = 224

def clean_and_rename_images(root_path):
    files_to_delete = []  # 保存因权限问题暂时无法删除的文件

    # 遍历目录
    for root, dirs, files in os.walk(root_path):
        for file_name in files:
            file_path = os.path.join(root, file_name)
            file_ext = os.path.splitext(file_name)[1].lower()
            if file_ext in ALLOWED_EXTS:
                # 如果文件是图片,检查图片是否有问题
                if not check_pic(file_path, files_to_delete):
                    continue  # 如果图片有问题,跳过重命名
            else:
                # 如果文件不是图片,尝试删除
                try:
                    os.remove(file_path)
                except (PermissionError, FileNotFoundError, OSError) as e:
                    print(f"删除文件 {file_path} 失败: {e}")

    # 重命名图片文件
    for subfolder in get_subfolders(root_path):
        rename_image_files_in_subfolder(subfolder, os.path.basename(subfolder), files_to_delete)

    # 尝试删除权限问题下未能删除的文件
    for file_path in files_to_delete:
        try:
            os.remove(file_path)
        except (FileNotFoundError, OSError) as e:
            print(f"删除文件 {file_path} 失败: {e}")

# 获取指定目录下的所有子文件夹
def get_subfolders(path):
    return [os.path.join(path, o) for o in os.listdir(path) if os.path.isdir(os.path.join(path, o))]

# 检查图片是否有问题并记录问题图片
def check_pic(path_pic, files_to_delete):
    try:
        with Image.open(path_pic) as img:
            img.verify()  # 只用于验证图片,不加载图片数据
        with Image.open(path_pic) as img:
            img.load()  # 加载图片数据,确保没有问题
            if img.width < MIN_DIMENSION or img.height < MIN_DIMENSION:
                raise ValueError(f"Image dimensions are too small: {img.size}")
        return True
    except (FileNotFoundError, OSError, ValueError) as e:
        with open('False.txt', 'a+') as f:
            f.write(str(path_pic) + '\n')
        try:
            os.remove(path_pic)
        except PermissionError:
            files_to_delete.append(path_pic)
        return False

# 重命名指定目录下的所有图片文件
def rename_image_files_in_subfolder(subfolder, subfolder_name, files_to_delete):
    unique_index = 0
    for file_name in os.listdir(subfolder):
        file_path = os.path.join(subfolder, file_name)
        file_ext = os.path.splitext(file_name)[1].lower()
        if file_ext in ALLOWED_EXTS:
            # 构建目标文件名,并确保它是唯一的
            new_file_name = f"{subfolder_name}_{unique_index + 1}{file_ext}"
            new_file_path = os.path.join(subfolder, new_file_name)
            while os.path.exists(new_file_path):  # 如果目标文件名存在,递增序号直到找到唯一的文件名
                unique_index += 1
                new_file_name = f"{subfolder_name}_{unique_index + 1}{file_ext}"
                new_file_path = os.path.join(subfolder, new_file_name)
            os.rename(file_path, new_file_path)
            unique_index += 1

if __name__ == '__main__':
    clean_and_rename_images(".")  # 从当前目录开始处理


扫描二维码推送至手机访问。

版权声明:本文由我的FPGA发布,如需转载请注明出处。

本文链接:https://myfpga.cn/index.php/post/421.html

分享给朋友:

“Smart Image Organizer Assistant 图片数据集重命名、清理,去重错误文件 Python实现” 的相关文章

math库的使用

math库的使用

math库包括4个数学常数math.pi      圆周率math.e       自然对数math.inf     正无穷大,负无穷大为-math.infmath.nan     非浮点数标记math库常用函数math.cell(x)      向上取整,返回不小于x的最小整数math.facto...

  索引运算符【】

索引运算符【】

选择字符串的子序列语法【start:finish】        start:子序列开始位置的索引值        finish:子序列结束位置的下一个字符的索引值如果不提供start或者finish,默认start为第一个字符,finish为最后一个字符。例如>>>my_str=...

顺序查找

顺序查找

如果需要查找某个特定值的位置(以便能够替换或删除它),可以直接使用index方法。searchedValue=100 #values是之前定义好的一个列表 if searchedValue in walues:     pos=values.index(searchedValue)     ...

anaconda打不开的解决方法

anaconda打不开的解决方法

报错内容Navigator Error An unexpected error occurred on Navigator start-up Report Please report this ...

(原创)使用Python对任意网站图片进行爬取,仅用于学习

(原创)使用Python对任意网站图片进行爬取,仅用于学习

import os import time import argparse import requests import re import io from urllib.parse import ...

(原创)使用Python递归获取网页内的所有URL,并进行清洗

(原创)使用Python递归获取网页内的所有URL,并进行清洗

import argparse import time from urllib.parse import urljoin, urlparse from selenium import webdriver...