Python应用 - 自动裁切帧动画的透明区域

程序运行界面

运行结果对比

前:

后:

详细使用文档 和 应用下载

Docs

思路:

1. 我们需要获取所有帧动画的共同外边框  切出来的时候 保证图片大小一样

     所以我们需要 通过遍历所有帧 获取他们的公共外边框

 2. 我们只需要将所有图片按照这个外边框剪切即可

如果你用的不是Python语言 按照上面那个思路也work

例如c++的话 你只需要将公共外边框内的 像素拷贝到一个新的图片对象中 并保存到本地 即可

  

源码:

crop.py

# -*- coding:utf-8 -*-
from PIL import Image
import os
import time
import numpy as np  # 获取图片像素
from gevent import monkey; monkey.patch_all()
import gevent
from progressBar import ProgressBar
import consoleColorFont

while True:

    #文件路径输入
    baseurl = input('Input the file root of the animation frame. or enter "exit" quit appliction\n')
    if baseurl.lower() == 'exit':
        break
    baseurl = baseurl.replace('\\', '/')
    files = os.listdir(baseurl)
    print(f'\n\nconvert path: {baseurl}')
    resulturl = baseurl + '_result' #resulturl = baseurl.replace(f'/{os.path.split(baseurl)[1]}', '/result')
    print(f'publish path: {resulturl}')
    if not os.path.exists(resulturl):
        os.makedirs(resulturl)
    
    i = 0
    start = time.time() #计时开始
    bar = ProgressBar(total = len(files))
    tmloaded = 0
    maxload = len(files)
    consoleColorFont.printYellow(f"\nestimated run time of {round(1.484*maxload,2)} seconds")
    
    imgtable = []
    imgtable.append([])
    imgtable.append([])
    def loadImg(url):
        global i
        img = Image.open(url)
        suffix = os.path.splitext(url)[-1]
        save_dir = f'{resulturl}/{i}{suffix}'
        i += 1
        imgtable[0].append(save_dir)
        imgtable[1].append(img)
        bar.step()
    
    tasks = []
    for file in files:
        url = f'{baseurl}/{file}'
        tasks.append(gevent.spawn(loadImg,url))
    
    print("\nLoad and cache images:")
    gevent.joinall(tasks)
    print("cache images finish.\n\n")
    
    x_min = 4096
    y_min = 4096
    x_max = 0
    y_max = 0
    _rows = 4096
    _cols = 4096
    
    def get_bounding_box(buffer, rows, cols):
        global x_max
        global x_min
        global y_max
        global y_min
        global tmloaded
        for i in range(rows):
            for j in range(cols):
                if buffer[i, j][3] > 0:
                    if j < x_min:
                        x_min = j
                    if j > x_max:
                        x_max = j
                    if i < y_min:
                        y_min = i
                    if i > y_max:
                        y_max = i
        bar.step(f"progress: {round(tmloaded/maxload*100,2)}% ")
        tmloaded += 1
    
    def run(imgtable):
        global _cols
        global _rows
        tasks = []
        bar.count = 0
        for i in range(maxload):
            buffer = np.array(imgtable[1][i])
            rows, cols, dims = buffer.shape
            _cols = min(cols, _cols)
            _rows = min(rows, _rows)
            task = gevent.spawn(get_bounding_box, buffer, rows, cols)
            tasks.append(task)
        print("Traverse all image pixels Calculate the outer border:")
        gevent.joinall(tasks)
        print("Outer border statistics are complete.\n\n")

    #遍历 所有图片像素; 计算 外边框
    run(imgtable)

    #形状
    _x = max(0, x_min-1)
    _y = max(0, y_min-1)
    x_ = min(_cols, x_max + 1)
    y_ = min(_rows, y_max + 1)
    
    #输出
    for i in range(maxload):
        imgtable[1][i].crop((_x, _y, x_, y_)).save(imgtable[0][i])
    print(f"\n\n===========输出信息=============\nbounding-box {x_min},{y_min} {x_max},{y_max}\ncrop count:{len(files)}\nruntime: {round(time.time()-start,2)}s\n===========输出结束=============")

progressBar.py

import sys, time

from pkg_resources import yield_lines

class ProgressBar:
    def __init__(self, count = 0, total = 0, width = 50):
        self.count = count
        self.total = total
        self.width = width
    def step(self,r = None):
        self.count += 1
        sys.stdout.write(' ' * (self.width + 9) + '\r')
        sys.stdout.flush()
        
        progress = round( self.width * self.count / self.total )
        if r:
            sys.stdout.write(r)
        else:
            sys.stdout.write('{0:3}/{1:3}: '.format(self.count, self.total))
        sys.stdout.write('■' * progress + '□' * (self.width - progress) + '\r')

        if progress == self.width:
            sys.stdout.write('\n')
        sys.stdout.flush()


# bar = ProgressBar(total = 10,width=10)
# for i in range(10):
#     bar.step()
#     time.sleep(1)

Guess you like

Origin blog.csdn.net/qq_39162566/article/details/118386676