多线程截取视频为每帧

1 多线程截取视频为每帧

功能: 将多个视频文件进行抽帧,每个视频开启一个线程

#!/usr/bin/python3.6
# -*- coding: utf-8 -*-
# @Time    : 2021/5/10 14:32
# @Author  : 
# @File    : MutiThreadVideeo2Image.py


from threading import Thread
import threading
import math, time, queue
import datetime
from tqdm import tqdm
from termcolor import cprint
import json
import numpy as np
import cv2
from pathlib import Path


class MyThread:

    def __init__(self, color='g'):
        self.color = color
        self.t_n = 0  ## 总线程数
        self.f_n = 0  ## 已完成线程数
        self.startTime = time.time()  ## 开始时间
        self.q = queue.Queue()  ## 收集容器
        self.pro = True  ## 是否打印进度条

    def progressBar(self, f_n, t_n):  ## 进度条
        if not self.pro:
            return
        if self.f_n < self.t_n:
            end = ""
        else:
            self.pro = False
            end = "\n"

        n = f_n / t_n  ## 计算完成率

        elapsedTime = datetime.timedelta(seconds=int(time.time() - self.startTime))
        sta_s = int(time.time() - self.startTime) / f_n * (t_n - f_n)  ## 已用时间
        eta = datetime.timedelta(seconds=int(sta_s))  ## 还需时间估计

        cprint("\r" + "({} of {})".format(f_n, t_n).ljust(2 * len(str(t_n)) + 6) + " [" +
               ("=" * int(100 * n / 2) + ">").ljust(50) + "] {}%".format(round(n * 100, 2)).ljust(8) +
               "  Elapsed Time: {}  ETA: {}".format(elapsedTime, eta) + end, color='green', end='')

    def splitList(self, n, dataList):
        """
        将一个列表分成 n 份
        :param n:
        :param dataList:
        :return:
        """
        per_th = math.ceil(len(dataList) / n)
        res = []
        for i in range(n):
            res.append(dataList[per_th * i:per_th * (i + 1)])
        return res

    def target(self, fun, args, sema, q):
        """
        :param fun: 函数
        :param args: 参数列表或元组, 或是带参数名的字典
        :param sema:
        :return:
        """
        with sema:
            try:
                if type(args) == list or type(args) == tuple:
                    fun(*args)
                else:
                    fun(**args)
                self.f_n += 1
                if self.pro:  ## 打印进度条
                    self.progressBar(self.f_n, self.t_n)

            except Exception as e:
                self.f_n += 1
                cprint("\r" + repr(e), 'red', end="\n")
                print("args: " + json.dumps(args))  ## 红色输出错误, 白色打印出参数信息
                if self.pro:  ## 打印进度条
                    self.progressBar(self.f_n, self.t_n)

    def mul_thread(self, n, fun, argsList, timeout=None, color='g'):
        """
        多线程执行
        :param n: 同时开启的线程数
        :param fun: 函数
        :param argsList: 每个函数的参数, 列表形式
        :param timeout: 每个线程限制的时间
        :return: 以队列形式返回执行失败的参数
        """
        self.__init__()
        self.t_n = len(argsList)
        self.color = color

        sema = threading.Semaphore(value=n)  ## 同时开启 n_t 个进程
        threads = []
        for args in argsList:
            threads.append(Thread(target=self.target, args=(fun, args, sema, self.q)))
        for thread in threads:  ## 开启所有进程
            thread.start()
        for thread in threads:  ## 等待所有线程完成
            thread.join(timeout)

        return self.q

    def __call__(self, *args, **kwargs):
        return self.mul_thread(*args, **kwargs)


def video2image(video_path, save_path, step=20, start=0., end=None, calHath=True): ## 将从视频中抽取图片
    """

    :param video_path:  待截取视频的路径
    :param save_path:   截取后文件保存路径
    :param step: 应该是多少帧
    :param start:
    :param end:
    :param calHath:
    :return:
    """
    path = Path(save_path)
    if not path.exists():
        path.mkdir()
    vc = cv2.VideoCapture(str(video_path))
    opened = vc.isOpened()
    if not opened:
        cprint("视频打开错误", "red")
        return
    fps = vc.get(cv2.CAP_PROP_FPS)  ## 获取视频帧率
    count = int(vc.get(cv2.CAP_PROP_FRAME_COUNT))  ## 获取视频总帧数
    width = int(vc.get(cv2.CAP_PROP_FRAME_WIDTH))  ## 获取视频宽度
    height = int(vc.get(cv2.CAP_PROP_FRAME_HEIGHT))  ## 获取视频高度
    cprint(f"视频宽度: {width}, 视频高度: {height}, 视频总帧数: {count}, 视频帧率: {fps}", "cyan")
    time.sleep(0.01)
    start_frame = 0
    if start:
        start_frame = min(int(start * fps), count)  # 开始帧
        vc.set(cv2.CAP_PROP_POS_FRAMES, start_frame)  ## 设置视频的开始帧位置
    if end:
        count = min(int(end * fps), count)
    count -= start_frame
    pbar = tqdm(total=count, desc="进度")  ## 进度条
    f_num = 0  ## 读取视频的帧数
    while opened:
        f_num += 1
        opened, frame = vc.read()
        if opened and f_num % step == 0:
            n = f_num // step
            img_path = str(path / (str(n).rjust(6, '0') + '.jpg'))
            cv2.imwrite(img_path, frame)
            if calHath:
                with open(str(path / "hash.txt"), 'a+') as f:
                    hash_str_8 = aHash(frame)
                    hash_str_16 = aHash(frame, 16)
                    f.write(str(img_path) + "," + hash_str_8 + "," + hash_str_16 + "\n")
            if f_num == count:
                break
        pbar.update(1)
    pbar.close()
    vc.release()
    cv2.destroyAllWindows()
    cprint("Done!", "green")


def aHash(img, n=8): #均值哈希算法
    img = cv2.resize(img, (n, n))
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    avg = np.mean(gray)
    res = (gray > avg).astype(np.int).astype(np.str).tolist()
    hash_str = "".join(["".join(item) for item in res])
    return hash_str


if __name__ == '__main__':
    param = [
        [r"C:\Users\xx\Desktop\lldvideo\tiqu\front1_20211129124640.mp4", r"C:\Users\xx\Desktop\lldvideo\tiqu\frame", 100],  # 视频路径;文件保存路径;按每100帧截取一帧,
        # [r'F:\exper\o2\38/2.mp4', r"F:\results/2", 1],
        # [r'F:\exper\o2\38/3.mp4', r"F:\results/3", 1],
        # [r'F:\exper\o2\38/4.mp4', r"F:\results/4", 1],
        # [r'F:\exper\o2\38/5.mp4', r"F:\results/5", 1],
        # [r'F:\exper\o2\38/6.mp4', r"F:\results/6", 1],
        # [r'F:\exper\o2\38/7.mp4', r"F:\results/7", 1],
        # [r'F:\exper\o2\38/8.mp4', r"F:\results/8", 1],
        # [r'F:\exper\o2\38/9.mp4', r"F:\results/9", 1],
    ]

    b = MyThread()

    b(10, video2image, param)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值