最近组了一个磁盘阵列,存储了大量的素材视频,需要分类,挨个预览属实麻烦,于是写了个基于间隔帧的合并摘要代码

import os

import cv2
import numpy as np
from PIL import Image, ImageDraw, ImageFont


class VideoImageSummary:

    def __init__(self, path, cols=3, rows=8):
        self._cap = cv2.VideoCapture(path)
        self._frame_count = int(self._cap.get(cv2.CAP_PROP_FRAME_COUNT))
        self._fps = self._cap.get(cv2.CAP_PROP_FPS)
        self._frame_width = int(self._cap.get(cv2.CAP_PROP_FRAME_WIDTH))
        self._frame_height = int(self._cap.get(cv2.CAP_PROP_FRAME_HEIGHT))

        # 视频秒数
        self._duration = self._frame_count / self._fps

        # 期望排列内容
        self._cols = cols
        self._rows = rows
        # 间隔像素
        self._space = 10

        self.filepath, self.filename = os.path.split(path)
        self.filesize = round(os.path.getsize(path) / 1024 / 1024, 2)

    # 截取数量
    @property
    def frames_intercepted_count(self):
        return int(self._frame_count // (self._cols * self._rows))

    def create_background_image(self, height=0, width=0):
        # 创建画布
        img_height = self._frame_height * self._rows + self._space * (self._rows + 1) + height
        img_width = self._frame_width * self._cols + self._space * (self._cols + 1) + width
        img = np.zeros((img_height, img_width), np.uint8)
        img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
        img[:, :, :] = 255
        return img

    def add_image_to_background(self, background_image, frame, x, y):
        background_image[y:y + self._frame_height, x:x + self._frame_width] = frame
        return background_image

    def img_add_text_utf8(self, img, text, xOffset=0, yOffset=0, size=20):
        img_cv2_RGB = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)  # cv2和PIL中颜色的hex码的储存顺序不同
        img_PIL = Image.fromarray(img_cv2_RGB)

        draw = ImageDraw.Draw(img_PIL)
        font = ImageFont.truetype("SimHei.ttf", size, encoding="utf-8")  # 参数1:字体文件路径,参数2:字体大小
        draw.text((xOffset, yOffset), text, (255, 255, 255), font=font)  # 参数1:打印坐标,参数2:文本,参数3:字体颜色,参数4:字体

        # PIL图片转cv2 图片
        img_cv2_textAdded = cv2.cvtColor(np.array(img_PIL), cv2.COLOR_RGB2BGR)
        return img_cv2_textAdded

    def write_video(self, img):
        img = self.img_add_text_utf8(img, "视频名称: %s" % self.filename, 5, 5, size=30)
        img = self.img_add_text_utf8(img, "视频时长: %s秒" % self._duration, 5, 37)
        img = self.img_add_text_utf8(img, "视频大小: %sMB" % self.filesize, 5, 58)
        img = self.img_add_text_utf8(img, "分辨率: %dx%d" % (self._frame_width, self._frame_height), 5, 80)
        return img

    def main(self):
        background_image = self.create_background_image(height=300)
        # 基础信息写入
        background_image = self.write_video(background_image)

        current_row, current_col = 0, 0
        for i in range(self._frame_count):
            if i == self._fps - (self._fps // 2):
                self._cap.set(cv2.CAP_PROP_POS_FRAMES, i)
                ret, frame = self._cap.read()
                cv2.imwrite('cover.png', frame)

            if i % self.frames_intercepted_count != 0 or i == 0:
                continue
            self._cap.set(cv2.CAP_PROP_POS_FRAMES, i)
            ret, frame = self._cap.read()
            if not ret:
                break

            x = current_col * (self._frame_width + self._space)
            y = current_row * (self._frame_height + self._space) + 100

            current_col += 1
            if current_col >= self._cols:
                current_col = 0
                current_row += 1
                if current_row >= self._rows:
                    current_row = 0

            # 多少秒
            seconds = i / self._fps
            # 多少分钟
            minutes = seconds / 60
            # 多少小时
            hours = minutes / 60

            text = f'{hours:.0f}:{minutes:.0f}:{seconds:.0f}'

            frame = self.img_add_text_utf8(frame, text, 10, 10)
            background_image = self.add_image_to_background(background_image, frame, x, y)
        cv2.imwrite('test.png', background_image)