题目

#从网上下载或自己手机录制一段视频(>30秒),第0-5秒显示一句话的字幕,第6-15秒显示另一句话的字幕。
#第20秒开始从屏幕中心出现一个光点,发出眩光,逐渐扩大覆盖的整个屏幕(类似太阳),最后光点缩小复原,整个过程10秒。

先给出框架

opencv视频添加文字水印 opencv添加字幕_opencv视频添加文字水印

data文件夹(文末有链接)

.mp4文件可以选取自己的视频,图片是你要生成的眩光效果,相应的要改utils。

gen_glareRGB.py

##gen_glareRGB.py##
#获取眩光图片的像素分布,是调用的函数,下次放在modules模块里面会更好
import cv2

def GlaredgeRgb():
    #这里是我们需要获取的眩光半径343个像素,是取了视频高度的一半
    radius_rgb = [0]*343
    glare_data = cv2.imread('../data/glare.jpg')
    glare_data = cv2.cvtColor(glare_data,cv2.COLOR_BGR2RGB)
    row,col,cha = glare_data.shape
    #选择中心的那一行
    chose_row=int(row/2)
    #从第300列开始,获取像素值
    chose_col = 300
    for i in range(len(radius_rgb)):
        radius_rgb[i] = tuple(glare_data[chose_row,i+chose_col])
    return radius_rgb[266:343]  #343-77=266,是由于在这之内的像素全是白色,只取非白色点

if __name__ == '__main__':
    a = GlaredgeRgb()
    print(a)
    count = 0
    for i in range(len(a)):
        #找非白色点有多少个
        if a[i][0] != 255:
            print(i)
            count +=1
    print(count) #77
    print(count/len(a))  #0.2244,计算非白色点的比率

SubtitlesVideo1.py

加上字幕,生成第一种眩光,时间花费较短,20s左右,效果中下。

##SubtitlesVideo1.py##
#从网上下载或自己手机录制一段视频(>30秒),第0-5秒显示一句话的字幕,第6-15秒显示另一句话的字幕。
#第20秒开始从屏幕中心出现一个光点,发出眩光,逐渐扩大覆盖的整个屏幕(类似太阳),最后光点缩小复原,整个过程10秒。
#这个光照实现的不够好,是比较生硬的感觉
import datetime
import time

# 方法一:datetime.datetime.now() 时间和日期的结合 eg: 2021-10-15 14:19:27.875779
#——————————————————————————————————————————————————————————————————————#
start_dt = datetime.datetime.now()
print("start_datetime:", start_dt)
time.sleep(2)
for i in range(10000):
    i += 1
#——————————————————————————————————————————————————————————————————————#

import cv2
from utils.gen_glareRGB import GlaredgeRgb

def glare_circle(img = '../data/glare.jpg',center = (30,30),radius=3):
    edge_i = 0
    glare_edge =  GlaredgeRgb()
    cent_rate = 0.78
    cv2.circle(img,center,int(radius*cent_rate),(255,255,255),-1)
    for i in range(int(radius*cent_rate)+1,radius+1):
        if edge_i >= len(glare_edge):
            edge_i = len(glare_edge)  - edge_i%len(glare_edge) -1
        cv2.circle(img,center,i,tuple([int(x) for x in glare_edge[edge_i]]),0)
        edge_i += 1
    return 0

#original_video
org_video = "../data/LawerCrush.mp4"
#video_subtitled
sub_video = "../data/LawerCrush_subtitles1.mp4"
#read video
Video = cv2.VideoCapture(org_video)
#Gets the video frame rate
Fps_video = Video.get(cv2.CAP_PROP_FPS)
#Sets the encoding format for writing video
fourcc = cv2.VideoWriter_fourcc(*"mp4v")
#Get video width
frame_width = int(Video.get(cv2.CAP_PROP_FRAME_WIDTH))
#Get video Height
frame_height = int(Video.get(cv2.CAP_PROP_FRAME_HEIGHT))
#Save the video after the subtitles
videoWriter = cv2.VideoWriter(sub_video, fourcc, Fps_video, (frame_width, frame_height))

##Add subtitles
glare_time = int(Fps_video*5)-1 #vanish overflow
glare_count = 0
frame_id = 0
w_index = 0
putword = ['He is a down-and-out lawyer','God gave him another surprise','  ']
cc_x = int(frame_width/2)
cc_y = int(frame_height/2)
while (Video.isOpened()):
    ret, frame = Video.read()
    if ret == True:
        frame_id += 1
        time_s = int(frame_id/Fps_video)
        if(time_s<6):
            w_index = 0
        elif(time_s<16):
            w_index = 1
        else:
            w_index =2
            if 20<time_s <= 25 :
                glare_count += 1
            elif 25< time_s <=30:
                glare_count -= 1
        #full
        glare_circle(frame,(cc_x,cc_y),int((cc_x/glare_time)*glare_count))
        #Text coordinates
        word_x = 450
        word_y = int(frame_height)-18
        cv2.putText(frame, '%s' %putword[w_index], (word_x, word_y), cv2.FONT_HERSHEY_SIMPLEX, 2, (255,255,255), 2)
        #****写入视频
        videoWriter.write(frame)
    else:
        videoWriter.release()
        break

#——————————————————————————————————————————————————————————————————————#
end_dt = datetime.datetime.now()
print("end_datetime:", end_dt)
print("time cost:", (end_dt - start_dt).seconds, "s")
#——————————————————————————————————————————————————————————————————————#

SubtitlesVideo2.py

加上字幕,生成第二种眩光,时间花费较长,30min左右,效果很好。

##SubtitlesVideo2.py##
#从网上下载或自己手机录制一段视频(>30秒),第0-5秒显示一句话的字幕,第6-15秒显示另一句话的字幕。
#第20秒开始从屏幕中心出现一个光点,发出眩光,逐渐扩大覆盖的整个屏幕(类似太阳),最后光点缩小复原,整个过程10秒。
#这个光照实现比较自然

import cv2
import math
import numpy as np
import datetime
import time

# 方法一:datetime.datetime.now() 时间和日期的结合 eg: 2021-10-15 14:19:27.875779
#——————————————————————————————————————————————————————————————————————#
start_dt = datetime.datetime.now()
print("start_datetime:", start_dt)
time.sleep(2)
for i in range(10000):
    i += 1
#——————————————————————————————————————————————————————————————————————#

#original_video
org_video = "../data/LawerCrush.mp4"
#video_subtitled
sub_video = "../data/LawerCrush_subtitles2.mp4"
#read video
Video = cv2.VideoCapture(org_video)
#Gets the video frame rate
Fps_video = Video.get(cv2.CAP_PROP_FPS)
#Sets the encoding format for writing video
fourcc = cv2.VideoWriter_fourcc(*"mp4v")
#Get video width
frame_width = int(Video.get(cv2.CAP_PROP_FRAME_WIDTH))
#Get video Height
frame_height = int(Video.get(cv2.CAP_PROP_FRAME_HEIGHT))
#Save the video after the subtitles
videoWriter = cv2.VideoWriter(sub_video, fourcc, Fps_video, (frame_width, frame_height))

##Add glare
strength = 222
centerx = frame_width/2
centery = frame_height/2
#full
radius = max(centerx,centery)
glare_time = int(Fps_video*5)-1  #5s一个阶段
glare_count = 0

def glaring(frame,r):
    if r == 0:
        return 0
    for i in range(frame_height):
        for j in range(frame_width):
            distance  = math.pow((centery-i),2) + math.pow((centerx-j),2)
            #获取原始图像
            B = frame[i, j][0]
            G = frame[i, j][1]
            R = frame[i, j][2]
            if (distance<r*r):
                #按照距离大小计算增强的光照值
                result = (int)(strength * (1.0 -math. sqrt(distance) / radius))
                B = frame[i, j][0] + result
                G = frame[i, j][1] + result
                R = frame[i, j][2] + result
                #判断边界防止越界
                B = min(255, max(0, B))
                G = min(255, max(0, G))
                R = min(255, max(0, R))
                frame[i, j] = np.uint8((B, G, R))
            else:
                frame[i, j] = np.uint8((B, G, R))

#______________________________________________#

##Add subtitles

frame_id = 0
w_index = 0
putword = ['He is a down-and-out lawyer','God gave him another surprise','  ']
#______________________________________________#
while (Video.isOpened()):
    ret, frame = Video.read()
    if ret == True:
        frame_id += 1
        print(frame_id)
        time_s = int(frame_id/Fps_video)
        if(time_s<6):
            w_index = 0
        elif(time_s<16):
            w_index = 1
        else:
            w_index =2
            if time_s<=20:
                glare_count = 0
            elif 20<time_s <= 25 :
                print('therebig{}'.format(frame_id))
                glare_count +=1
            elif 25< time_s <=30:
                glare_count -=1
                print('theresmalll{}'.format(frame_id))
            if frame_id%1 == 0:
                glaring(frame,(radius/glare_time )*glare_count)
        #Text coordinates
        word_x = 450
        word_y = int(frame_height)-18
        cv2.putText(frame, '%s' %putword[w_index], (word_x, word_y), cv2.FONT_HERSHEY_SIMPLEX, 2, (255,255,255), 2)
        #****写入视频
        videoWriter.write(frame)
    else:
        videoWriter.release()
        break

#——————————————————————————————————————————————————————————————————————#
end_dt = datetime.datetime.now()
print("end_datetime:", end_dt)
print("time cost:", (end_dt - start_dt).seconds, "s")
#——————————————————————————————————————————————————————————————————————#

运行结果

运行SubtitlesVideo1.py之后,在data文件夹会多出来一个视频

opencv视频添加文字水印 opencv添加字幕_opencv视频添加文字水印_02


查看视频完成要求情况:

opencv视频添加文字水印 opencv添加字幕_python_03


opencv视频添加文字水印 opencv添加字幕_ci_04


opencv视频添加文字水印 opencv添加字幕_ide_05


运行SubtitlesVideo2.py之后,在data文件夹又会多出来一个视频

opencv视频添加文字水印 opencv添加字幕_python_06


查看视频完成要求情况(主要是眩光有变化):

opencv视频添加文字水印 opencv添加字幕_ci_07

第三种美丽的眩光,并且耗时短,是由W同学的好想法(见代码)做到的

e2_main_acc.py

import cv2
import os
from tqdm import tqdm
import numpy as np
from PIL import Image, ImageDraw, ImageFont
import multiprocessing


# 切割图像帧
def get_each_frame(video_path):
    # 读取视频文件
    video = cv2.VideoCapture(video_path)
    _, frame = video.read()
    fps = video.get(cv2.CAP_PROP_FPS)
    frames = video.get(cv2.CAP_PROP_FRAME_COUNT)
    frames = int(frames)
    print('开始切割图像帧....')
    print('*' + 50 * '-' + '*')
    for i in tqdm(range(1, frames + 1)):
        address = './per_picture/' + str(i) + '.jpg'
        cv2.imwrite(address, frame)
        _, frame = video.read()
    return frames, int(fps)


# 合成图像帧为视频
def merge_image_to_video(folder_name, per_h, per_w, fps, n):
    fourcc = cv2.VideoWriter_fourcc(*'mp4v')
    img_size = (per_w, per_h)
    video = cv2.VideoWriter("output.mp4", fourcc, fps, img_size)
    print('开始合成图像帧....')
    print('*' + 50 * '-' + '*')
    for f1 in tqdm(range(1, n + 1)):
        f1 = str(f1) + '.jpg'
        filename = os.path.join(folder_name, f1)
        frame = cv2.imread(filename)
        frame = cv2.resize(frame, img_size, interpolation=cv2.INTER_CUBIC)
        video.write(frame)
    video.release()


# 添加字幕
def add_text(s, e, t, h, w):
    # 字幕参数设置
    pos = (w // 3, h - 100)
    t_color = (0, 255, 255)
    t_size = 60
    print('开始添加字幕....')
    print('*' + 50 * '-' + '*')
    for i in tqdm(range(s, e + 1)):
        path = './per_picture/' + str(i) + '.jpg'
        img = cv2.imread(path)
        img = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
        # 创建一个可以在给定图像上绘图的对象
        draw = ImageDraw.Draw(img)
        # 字体的格式
        font = ImageFont.truetype("simsun.ttc", t_size, encoding="utf-8")
        # 绘制文本
        draw.text(pos, t, t_color, font=font)
        # 转换回OpenCV格式
        img = cv2.cvtColor(np.asarray(img), cv2.COLOR_RGB2BGR)
        cv2.imwrite(path, img)


# 添加曝光点
def add_exposure(s, e, h, w, mode):
    if mode == 'up':
        r = 0.01
        v = (h ** 2 + w ** 2) ** (1 / 2) * 2 / (e - s + 1)
        print('增加逐渐增大的曝光点......')
    elif mode == 'down':
        r = (h ** 2 + w ** 2) ** (1 / 2) * 2
        v = -(h ** 2 + w ** 2) ** (1 / 2) * 2 / (e - s + 1)
        print('增加逐渐减小的曝光点......')
    print('*' + 50 * '-' + '*')
    for i in tqdm(range(s, e + 1)):
        r += v
        path = './per_picture/' + str(i) + '.jpg'
        img = cv2.imread(path)
        # 曝光点部分
        m1 = np.zeros((h, w, 3))
        I = np.arange(h)[:, None]
        J = np.arange(w)
        i_r = ((I - h // 2) ** 2 + (J - w // 2) ** 2) ** (1 / 2)
        p1 = i_r < r
        # 逻辑矩阵扣出曝光点区域
        q = 255 * (1 - i_r / r)
        # 渐变光强
        q = np.repeat(q, 3, axis=1)
        # 复制光强到B、G、R三个通道
        q = q.reshape((h, w, 3))
        m1[p1] = q[p1]
        img = img + m1
        # 曝光点区域加上渐变的光强
        cv2.imwrite(path, img)


if __name__ == '__main__':
    # 切割图像帧
    n, fps = get_each_frame('./test.mp4')
    # 获取每张图像长和宽
    image = cv2.imread('./per_picture/1.jpg')
    h, w, _ = image.shape

    # 第0-5秒 显示字幕:"你为什么离开?"
    text1 = multiprocessing.Process(target=add_text, args=(fps * 0 + 1, fps * 5, "你为什么离开?", h, w))
    # 第6-15秒显示另一句话的字幕 '我不会停留在—个地方看风景,我的目标是星辰大海'
    text2 = multiprocessing.Process(target=add_text, args=(fps * 6 + 1, fps * 15, '我不会停留在—个地方看风景,我的目标是星辰大海', h, w))
    # 增加逐渐变大的曝光点 20-25秒
    exposure1 = multiprocessing.Process(target=add_exposure, args=(fps * 20 + 1, fps * 25, h, w, 'up'))
    # 增加逐渐减小的曝光点 25-30秒
    exposure2 = multiprocessing.Process(target=add_exposure, args=(fps * 25 + 1, fps * 30, h, w, 'down'))
    text1.start()
    text2.start()
    exposure1.start()
    exposure2.start()
    text1.join()
    text2.join()
    exposure1.join()
    exposure2.join()
    # 合成图像帧为视频流
    merge_image_to_video('per_picture', h, w, fps=fps, n=n)

e2_main.py

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



# 切割图像帧
def get_each_frame(video_path):
    # 创建视频流对象
    video = cv2.VideoCapture(video_path)
    # 获取视频帧率
    fps = video.get(cv2.CAP_PROP_FPS)
    # 获取总帧数
    frames = video.get(cv2.CAP_PROP_FRAME_COUNT)
    frames = int(frames)
    print('开始切割图像帧....')
    print('*' + 50 * '-' + '*')
    for i in tqdm(range(1, frames + 1)):
        # 存储图片帧的位置
        address = './per_picture/' + str(i) + '.jpg'
        _, frame = video.read()
        cv2.imwrite(address, frame)
    return frames, int(fps)

# 合成图像帧为视频
def merge_image_to_video(folder_name, per_h, per_w, fps, n):
    # 设置视频流的格式
    fourcc = cv2.VideoWriter_fourcc(*'mp4v')
    # 封装图像帧格式为元组
    img_size = (per_w, per_h)
    # 传入 视频 的帧率 和图像帧大小
    video = cv2.VideoWriter("output.mp4", fourcc, fps, img_size)
    print('开始合成图像帧....')
    print('*' + 50 * '-' + '*')
    for f1 in tqdm(range(1, n + 1)):
        f1 = str(f1) + '.jpg'
        # 图像帧路径
        filename = os.path.join(folder_name, f1)
        # 获取图像
        frame = cv2.imread(filename)
        frame = cv2.resize(frame, img_size, interpolation=cv2.INTER_CUBIC)
        # 写入图像帧
        video.write(frame)
    video.release()


# 添加字幕
def add_text(s, e, t, h, w):
    # 字幕参数设置
    pos = (w // 3, h - 100)
    t_color = (0, 255, 255)
    t_size = 60
    print('开始添加字幕....')
    print('*' + 50 * '-' + '*')
    for i in tqdm(range(s, e + 1)):
        path = './per_picture/' + str(i) + '.jpg'
        img = cv2.imread(path)
        img = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
        # 创建一个可以在给定图像上绘图的对象
        draw = ImageDraw.Draw(img)
        # 字体的格式
        font = ImageFont.truetype("simsun.ttc", t_size, encoding="utf-8")
        # 绘制文本
        draw.text(pos, t, t_color, font=font)
        # 转换回OpenCV格式
        img = cv2.cvtColor(np.asarray(img), cv2.COLOR_RGB2BGR)
        cv2.imwrite(path, img)


# 添加曝光点
def add_exposure(s, e, h, w, mode):
    if mode == 'up':
        r = 0.01
        v = (h ** 2 + w ** 2) ** (1 / 2) * 2 / (e - s + 1)
    elif mode == 'down':
        r = (h ** 2 + w ** 2) ** (1 / 2) * 2
        v = -(h ** 2 + w ** 2) ** (1 / 2) * 2  / (e - s + 1)
    print('*' + 50 * '-' + '*')
    for i in tqdm(range(s, e + 1)):
        r += v
        path = './per_picture/' + str(i) + '.jpg'
        img = cv2.imread(path)
        # 曝光点部分
        m1 = np.zeros((h, w, 3))
        I = np.arange(h)[:, None]
        J = np.arange(w)
        i_r = ((I - h // 2) ** 2 + (J - w // 2) ** 2) ** (1 / 2)
        p1 = i_r < r
        q = 255 * (1 - i_r / r)
        q = np.repeat(q, 3, axis=1)
        q = q.reshape((h, w, 3))
        m1[p1] = q[p1]
        img = img + m1
        cv2.imwrite(path, img)


if __name__ == '__main__':
    # 切割图像帧
    n, fps = get_each_frame('./test.mp4')
    # 获取每张图像长和宽
    image = cv2.imread('./per_picture/1.jpg')
    h, w, _ = image.shape

    # 第0-5秒 显示字幕:"你为什么离开?"
    add_text(fps * 0 + 1, fps * 5, "你为什么离开?", h, w)
    # 第6-15秒显示另一句话的字幕 '我不会停留在—个地方看风景,我的目标是星辰大海'
    add_text(fps * 6 + 1, fps * 15, '我不会停留在—个地方看风景,我的目标是星辰大海', h, w)
    # 增加逐渐变大的曝光点 20-25秒
    print('增加逐渐增大的曝光点......')
    add_exposure(fps * 20 + 1, fps * 25, h, w, mode='up')
    print('增加逐渐减小的曝光点......')
    # 增加逐渐减小的曝光点 25-30秒
    add_exposure(fps * 25 + 1, fps * 30, h, w, mode='down')
    # 合成图像帧为视频流
    merge_image_to_video('per_picture', h, w, fps=fps, n=n)