当前位置: 代码网 > it编程>前端脚本>Python > Python脚本自动化实现为某个目录下的图片添加边框

Python脚本自动化实现为某个目录下的图片添加边框

2026年07月21日 Python 我要评论
功能介绍电脑启动时,自动执行该脚本,动态监听某个目录,对该目录下(包含子目录)未添加过边框的图片,添加边框(可设置边框宽度和颜色)功能实现图片处理框架选择目前python处理图片的两个比较流行的库:p

功能介绍

电脑启动时,自动执行该脚本,动态监听某个目录,对该目录下(包含子目录)未添加过边框的图片,添加边框(可设置边框宽度和颜色)

功能实现

图片处理框架选择

目前python处理图片的两个比较流行的库:pillow和opencv,本文采用两种方式实现,顺便比较一下两个库处理图片的性能差异

1.使用pillow实现

import os
from pil import image

class imageborderhandler:

    def __init__(self, source_folder: str, output_folder: str):
        self.source_folder = source_folder
        self.output_folder = output_folder
        if not os.path.exists(output_folder):
            os.mkdir(output_folder)

    def _get_source_file_abs_path(self, file_name: str):
        return os.path.join(self.source_folder, file_name)

    def _get_output_file_abs_path(self, file_name: str):
        return os.path.join(self.output_folder, file_name)
	
    def _prepare_output_abs_path(self, file_name: str):
        """
        检查输出路径,如果父级目录不存在,自动创建
        :param file_name: 待输出文件,可能含有父级目录
        """
        full_path = os.path.join(self.output_folder, file_name)
        if not os.path.exists(full_path):
            dir_item = self.output_folder
            for path_item in file_name.split(os.path.sep)[: -1]:
                dir_item += f'{os.path.sep}{path_item}'
                if not os.path.exists(dir_item):
                    os.mkdir(dir_item)

    def border_image(self, image_file_name: str, border_size=3, border_color=(212, 212, 212)):
        """
        为图片添加边框
        :param image_file_name: 待处理图片文件名
        :param border_size: 边框宽度,默认值3px
        :param border_color: 边框颜色,默认值为浅灰色
        :return: none
        """
        if not os.path.exists(self._get_source_file_abs_path(image_file_name)):
            return

        self._pillow_border_image(image_file_name, border_size=border_size, border_color=border_color)

    def _pillow_border_image(self, image_file_name: str, border_size: int, border_color):
        origin_image = image.open(self._get_source_file_abs_path(image_file_name))
        (w, h) = origin_image.size

        # 宽度为原始图片尺寸 + 两个border的尺寸
        border_image = image.new('rgb', (w + 2 * border_size, h + 2 * border_size), border_color)
        border_image.paste(origin_image, (border_size, border_size))
       
        self._prepare_output_abs_path(image_file_name)
        border_image.save(self._get_output_file_abs_path(image_file_name))

2.使用opencv实现

import os
import cv2

class imageborderhandler:

    def __init__(self, source_folder: str, output_folder: str):
        self.source_folder = source_folder
        self.output_folder = output_folder
        if not os.path.exists(output_folder):
            os.mkdir(output_folder)

    def _get_source_file_abs_path(self, file_name: str):
        return os.path.join(self.source_folder, file_name)

    def _get_output_file_abs_path(self, file_name: str):
        return os.path.join(self.output_folder, file_name)

    def _prepare_output_abs_path(self, file_name: str):
        """
        检查输出路径,如果父级目录不存在,自动创建
        :param file_name: 待输出文件,可能含有父级目录
        """
        full_path = os.path.join(self.output_folder, file_name)
        if not os.path.exists(full_path):
            dir_item = self.output_folder
            for path_item in file_name.split(os.path.sep)[: -1]:
                dir_item += f'{os.path.sep}{path_item}'
                if not os.path.exists(dir_item):
                    os.mkdir(dir_item)

    def border_image(self, image_file_name: str, border_size=3, border_color=(212, 212, 212)):
        """
        为图片添加边框
        :param image_file_name: 待处理图片文件名
        :param border_size: 边框宽度,默认值3px
        :param border_color: 边框颜色,默认值为浅灰色
        :return: none
        """
        if not os.path.exists(self._get_source_file_abs_path(image_file_name)):
            return

        self._open_cv_border_image(image_file_name, border_size=border_size, border_color=border_color)

    def _pillow_border_image(self, image_file_name: str, border_size: int, border_color):
        origin_image = image.open(self._get_source_file_abs_path(image_file_name))
        (w, h) = origin_image.size

        # 宽度为原始图片尺寸 + 两个border的尺寸
        border_image = image.new('rgb', (w + 2 * border_size, h + 2 * border_size), border_color)
        border_image.paste(origin_image, (border_size, border_size))

		self._prepare_output_abs_path(image_file_name)
        border_image.save(self._get_output_file_abs_path(image_file_name))

    def _open_cv_border_image(self, image_file_name: str, border_size: int, border_color: tuple):
        origin_image = cv2.imread(self._get_source_file_abs_path(image_file_name))
        bordered_image = cv2.copymakeborder(origin_image,
                                            border_size, border_size, border_size, border_size,
                                            cv2.border_constant, value=border_color)

		self._prepare_output_abs_path(image_file_name)
        cv2.imwrite(self._get_output_file_abs_path(image_file_name), bordered_image)

监听指定目录

自动在目标目录下创建一个隐藏文件processed_cache.txt(以.开头),存放已经添加过边框的图片文件名。该示例中监听的目录为:/users/jason315/desktop/test-image,将添加边框后的图片保存到/users/jason315/desktop/image-bordered目录下

关键代码如下

import os
import cv2
import time
from pil import image

class imageborderhandler:
	def __init__(self, source_folder: str, output_folder: str):
	   self.processed_cache_file = '.processed_cache.txt'
	   self.source_folder = source_folder
	   self.output_folder = output_folder
	
	   # 文件初始化
	   if not os.path.exists(output_folder):
	       os.mkdir(output_folder)
	   if not os.path.exists(self._get_processed_cache_abs_path()):
	       with open(self._get_processed_cache_abs_path(), 'w') as f:
	           f.flush()
	
	   # processed_cache初始化
	   self.processed_cache = set()
	   with open(self._get_processed_cache_abs_path(), 'r') as f:
	       for line in f.readlines():
	           self.processed_cache.add(line.replace('\n', ''))
       
	@staticmethod
    def _log_with_time(log_str):
        """
        打印日志, 格式[yyyy-mm-dd hh:mm:ss] 日志内容
        """
        print(f'[{time.strftime("%y-%m-%d %h:%m:%s")}] {log_str}')

	@staticmethod
    def _is_expected_image_file(file_name: str):
        suffix = file_name[file_name.rindex('.') + 1:]
        return suffix.lower() in ['png', 'jpeg', 'jpg']

    def _inner_process_file(self, the_file: str, processed_file_list: list[str]):
        file_name = the_file[the_file.rindex(os.path.sep) + 1:]
        if os.path.isdir(the_file):
            # 递归处理文件夹
            for file_item in os.listdir(the_file):
                self._inner_process_file(f'{the_file}/{file_item}', processed_file_list)
            return
        elif file_name.startswith('.') or not self._is_expected_image_file(file_name):
            return

        # 处理还未添加边框的图片
        path_under_source_folder = the_file.split(self.source_folder)[1]
        if path_under_source_folder.startswith(os.path.sep):
            path_under_source_folder = path_under_source_folder[1:]
        if path_under_source_folder not in self.processed_cache:
            self.border_image(path_under_source_folder)
            self.processed_cache.add(path_under_source_folder)
            processed_file_list.append(f'{path_under_source_folder}\n')

    def _inner_process(self):
        processed_file_list = []
        self._inner_process_file(self.source_folder, processed_file_list)
        if len(processed_file_list) > 0:
            with open(self._get_processed_cache_abs_path(), 'a') as f:
                f.writelines(processed_file_list)
                f.flush()
            self._log_with_time(f'add borders for {len(processed_file_list)} images')

    def start_process(self):
        """
        开始监听目标文件夹,每隔5秒处理1次
        :return:
        """
        self._log_with_time('the imageborderhandler starts working ...')
        while(true):
            self._inner_process()
            time.sleep(5)

if __name__ == '__main__':
    image_border_handler = imageborderhandler('/users/jason315/desktop/test-image', '/users/jason315/desktop/image-bordered')
    image_border_handler.start_process()

启动后添加一些图片到test-image目录下,观察输出日志

配置开机自启动

新建文件image-border-auto-start.sh,编写脚本,调用python启动main方法

cd /users/jason315/practice/pythonspace/jason-tool/com/jasonidea/tools
python ./image_border_handler.py

本文以macos设置开机自启动为例

1.修改自启动脚本运行权限

chmod 777 image-border-auto-start.sh

2.右键点击文件,修改打开方式

修改文件启动方式为terminal(终端)

3.设置 > 用户与群组 > 登录项

添加自启动脚本

完整代码

image_border_handler.py

import os
import cv2
import time
from pil import image


class imageborderhandler:

    def __init__(self, source_folder: str, output_folder: str):
        self.processed_cache_file = '.processed_cache.txt'
        self.source_folder = source_folder
        self.output_folder = output_folder

        # 文件初始化
        if not os.path.exists(output_folder):
            os.mkdir(output_folder)
        if not os.path.exists(self._get_processed_cache_abs_path()):
            with open(self._get_processed_cache_abs_path(), 'w') as f:
                f.flush()

        # processed_cache初始化
        self.processed_cache = set()
        with open(self._get_processed_cache_abs_path(), 'r') as f:
            for line in f.readlines():
                self.processed_cache.add(line.replace('\n', ''))

    def _get_processed_cache_abs_path(self):
        return os.path.join(self.source_folder, self.processed_cache_file)

    def _get_source_file_abs_path(self, file_name: str):
        return os.path.join(self.source_folder, file_name)

    def _get_output_file_abs_path(self, file_name: str):
        return os.path.join(self.output_folder, file_name)

    def _prepare_output_abs_path(self, file_name: str):
        """
        检查输出路径,如果父级目录不存在,自动创建
        :param file_name: 待输出文件,可能含有父级目录
        """
        full_path = os.path.join(self.output_folder, file_name)
        if not os.path.exists(full_path):
            dir_item = self.output_folder
            for path_item in file_name.split(os.path.sep)[: -1]:
                dir_item += f'{os.path.sep}{path_item}'
                if not os.path.exists(dir_item):
                    os.mkdir(dir_item)

    @staticmethod
    def _log_with_time(log_str):
        """
        打印日志, 格式[yyyy-mm-dd hh:mm:ss] 日志内容
        """
        print(f'[{time.strftime("%y-%m-%d %h:%m:%s")}] {log_str}')

    def border_image(self, image_file_name: str, border_size=3, border_color=(212, 212, 212)):
        """
        为图片添加边框
        :param image_file_name: 待处理图片文件名
        :param border_size: 边框宽度,默认值3px
        :param border_color: 边框颜色,默认值为浅灰色
        :return: none
        """
        if not os.path.exists(self._get_source_file_abs_path(image_file_name)):
            return

        self._open_cv_border_image(image_file_name, border_size=border_size, border_color=border_color)

    def _pillow_border_image(self, image_file_name: str, border_size: int, border_color):
        origin_image = image.open(self._get_source_file_abs_path(image_file_name))
        (w, h) = origin_image.size

        # 宽度为原始图片尺寸 + 两个border的尺寸
        border_image = image.new('rgb', (w + 2 * border_size, h + 2 * border_size), border_color)
        border_image.paste(origin_image, (border_size, border_size))

        self._prepare_output_abs_path(image_file_name)
        border_image.save(self._get_output_file_abs_path(image_file_name))

    def _open_cv_border_image(self, image_file_name: str, border_size: int, border_color: tuple):
        origin_image = cv2.imread(self._get_source_file_abs_path(image_file_name))
        bordered_image = cv2.copymakeborder(origin_image,
                                            border_size, border_size, border_size, border_size,
                                            cv2.border_constant, value=border_color)

        self._prepare_output_abs_path(image_file_name)
        cv2.imwrite(self._get_output_file_abs_path(image_file_name), bordered_image)

    @staticmethod
    def _is_expected_image_file(file_name: str):
        suffix = file_name[file_name.rindex('.') + 1:]
        return suffix.lower() in ['png', 'jpeg', 'jpg']

    def _inner_process_file(self, the_file: str, processed_file_list: list[str]):
        file_name = the_file[the_file.rindex(os.path.sep) + 1:]
        if os.path.isdir(the_file):
            # 递归处理文件夹
            for file_item in os.listdir(the_file):
                self._inner_process_file(f'{the_file}/{file_item}', processed_file_list)
            return
        elif file_name.startswith('.') or not self._is_expected_image_file(file_name):
            return

        # 处理还未添加边框的图片
        path_under_source_folder = the_file.split(self.source_folder)[1]
        if path_under_source_folder.startswith(os.path.sep):
            path_under_source_folder = path_under_source_folder[1:]
        if path_under_source_folder not in self.processed_cache:
            self.border_image(path_under_source_folder)
            self.processed_cache.add(path_under_source_folder)
            processed_file_list.append(f'{path_under_source_folder}\n')

    def _inner_process(self):
        processed_file_list = []
        self._inner_process_file(self.source_folder, processed_file_list)
        if len(processed_file_list) > 0:
            with open(self._get_processed_cache_abs_path(), 'a') as f:
                f.writelines(processed_file_list)
                f.flush()
            self._log_with_time(f'add borders for {len(processed_file_list)} images')

    def start_process(self):
        """
        开始监听目标文件夹,每隔5秒处理1次
        :return:
        """
        self._log_with_time('the imageborderhandler starts working ...')
        while(true):
            self._inner_process()
            time.sleep(5)


if __name__ == '__main__':
    image_border_handler = imageborderhandler('/users/jason315/desktop/test-image', '/users/jason315/desktop/image-bordered')
    image_border_handler.start_process()

以上就是python脚本自动化实现为某个目录下的图片添加边框的详细内容,更多关于python图片添加边框的资料请关注代码网其它相关文章!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2026  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com