Skip to content

生成视频序列帧

python
import os
from PIL import Image
import shutil
import json
import os,time,threading

fps_video_dir = 'fps_video'


def get_size(filename):
    # Obtain the file size: KB
    size = os.path.getsize(filename)
    return size / 1024

def compress_image(img_path, out_path, radio=0.05,mb=50, step=5, quality=100):
    """不改变图片尺寸压缩图像大小
    :param img_path: 压缩图像读取地址
    :param out_path: 压缩图像存储地址
    :param mb: 压缩目标,KB
    :param step: 每次调整的压缩比率
    :param quality: 初始压缩比率
    :return: 压缩文件地址,压缩文件大小
    """
    o_size = get_size(img_path)
    if o_size < mb:
        img = Image.open(img_path)
        img = img.convert('RGB')
        img.save(out_path, quality=quality)
        return Image.open(img_path)
    mb = o_size * radio

    img = Image.open(img_path)

    while o_size > mb:
        img = Image.open(img_path)
        img = img.convert('RGB')
        img.save(out_path, quality=quality)
        if quality - step < 0:
            break
        quality -= step
        o_size = get_size(out_path)

    print('File size: ' ,img_path,int(o_size))
    return img


def mp4_to_png(mp4):
    cmd = f'ffmpeg -i {mp4} -r 24 -f image2 ./{fps_video_dir}/img%05d.png'
    print(cmd)
    os.system(cmd)

def get_file_cnt(dir):
    cnt = 0
    for item in os.listdir(dir): 
        if item.endswith(".png"):
            cnt += 1
    return cnt

def generate_json(output_dir):
    cnt = get_file_cnt(fps_video_dir)
    data = json.dumps(dict(imgCnt=cnt))
    with open(os.path.join(output_dir,'config.json'),'w+') as file:
        file.write(data)

def compress(input_dir,output_dir):
    for item in os.listdir(input_dir):
        if not item.endswith(".png"):
            continue
        input_path = os.path.join(input_dir,item)
        
        out_jpg_path = os.path.join(output_dir,item.replace(".png",".jpg"))
        out_png_path = os.path.join(output_dir,item)
        compress_image(input_path,out_jpg_path)
        if not os.path.exists(out_jpg_path):
            raise Exception("文件不存在",out_jpg_path)
            # continue
        o_size = os.path.getsize(out_jpg_path) // 1024
        # print(o_size)
        shutil.copyfile(out_jpg_path,out_png_path)
        os.remove(out_jpg_path)

def compress_t(images,input_dir,output_dir):
    for item in images:
        if not item.endswith(".png"):
            continue
        input_path = os.path.join(input_dir,item)
        
        out_jpg_path = os.path.join(output_dir,item.replace(".png",".jpg"))
        out_png_path = os.path.join(output_dir,item)
        compress_image(input_path,out_jpg_path)
        if not os.path.exists(out_jpg_path):
            raise Exception("文件不存在",out_jpg_path)
            # continue
        o_size = os.path.getsize(out_jpg_path) // 1024
        # print(o_size)
        shutil.copyfile(out_jpg_path,out_png_path)
        os.remove(out_jpg_path)

def get_file_list(dir):
    ret = []
    for item in os.listdir(dir): 
        if item.endswith(".png"):
            ret.append(item)
    return ret

def compress_bat(fps_video_dir,output_dir):
    # group
    group_cnt = 5
    file_list = get_file_list(fps_video_dir)
    totle = len(file_list)
    padding = int(totle / group_cnt)+1
    
    image_list = []
    for i in range(0,len(file_list),padding):
        b=file_list[i:i+padding]
        print(b)
        image_list.append(b)
    cnt = 0
    for item in image_list:
        cnt += len(item)
    print (len(image_list),cnt)

    thread_list = []
    for thread_idx in range(group_cnt):
        thread_list.append(threading.Thread(target=compress_t, args=(image_list[thread_idx], fps_video_dir,output_dir,)))

    for item in thread_list:
        item.start()
    
    for item in thread_list:
        item.join()

def check_file_cnt(output_dir):
    src_cnt = get_file_cnt(fps_video_dir)
    dst_cnt = get_file_cnt(output_dir)
    return src_cnt,dst_cnt

def get_ts():
    now = int(time.time())
    timeArray = time.localtime(now)
    ts = time.strftime("%Y%m%d%H%M%S", timeArray)
    print (ts)
    return ts

def main(mp4):
    start =  int(get_ts())
    if not os.path.exists(fps_video_dir):
        os.makedirs(fps_video_dir)
    # clean input dir
    for item in os.listdir(fps_video_dir):
        os.remove(os.path.join(fps_video_dir,item))
    mp4_to_png(mp4)

    output_dir = os.path.basename(mp4).replace(".mp4",'')
    if not os.path.exists(output_dir):
        os.makedirs(output_dir)
    # clean output dir
    for item in os.listdir(output_dir):
        os.remove(os.path.join(output_dir,item))
    generate_json(output_dir)
    # compress(fps_video_dir,output_dir)
    compress_bat(fps_video_dir,output_dir)
    src_cnt,dst_cnt = check_file_cnt(output_dir)
    end = int(get_ts())
    print('用时',(end-start))
    if src_cnt != dst_cnt:
        print(src_cnt,dst_cnt)
        raise Exception("压缩过程中,图片数不匹配")

if __name__ == '__main__':
    # compress_image('fps_video/img01272.png','1c799f206d6d481a98cadf6d581ffb40/img01272.jpg')
    main('./1c799f206d6d481a98cadf6d581ffb40.mp4')