最近接到一个客户的订单,需要批量对电影片段截图,为了方便,于是我撸了一下午代码,写了这么一个辅助工具出来,希望对各位有相似需求的朋友们提供帮助。程序是用Python实现的。
大致思路:
1. 使用os.walk遍历当前目录(包括子目录)下所有文件,获得文件路径列表,再对列表中的文件分别处理。这里为了方便显示进度,我使用了tqdm来枚举列表。
2. 使用OpenCV的VideoCapture对视频等距截取9张图片。对视频截图的操作就像读文件时的操作,是存在一个视频帧的“指针”的,一帧图片截完了以后需要根据步长(ceil(总帧数/8)-1,减1是为了防止某些视频最后一帧为空而导致截图失败退出)更新指针。
3. 重点来了:将截取到的9张图片,每3张一组,使用np.concatenate横向拼接得到img0, img1, img2,最后将这三组图片用同样的方法纵向拼接得到img9,即为不带任何信息的纯九宫格图片。
关于numpy中矩阵拼接函数concatenate的用法,可以参考这篇博文:np.concatenate() 使用说明_Tchunren的博客-CSDN博客_np.concatenate([xi, x],axis=1
4. 使用cv2.copyMakeBorder在上述的img9的最上方画高为200的灰色边框,用于容纳视频的基本信息文字。然后获取视频的基本信息,包括文件大小、分辨率、时长、帧率等。
提示:opencv中获取分辨率使用cap.get(cv2.CAP_PROP_FRAME_HEIGHT),和cap.get(cv2.CAP_PROP_FRAME_WIDTH),分别取得帧的高和宽;
获取视频帧率使用cap.get(cv2.CAP_PROP_FPS);
获取视频时长,先使用cap.get(cv2.CAP_PROP_FRAME_COUNT)获取总帧数,再除以上述的帧率即可。
最后使用cv2.putText将上面的信息文字写入图片。
关于opencv中copyMakeBorder函数的用法,可以参考这篇博文:
OpenCV-Python: cv2.copyMakeBorder()函数详解_我是大黄同学呀的博客-CSDN博客_copymakeborder函数详解
关于opencv中putText函数的用法,可以参考这篇博文:
opencv中puttext()函数用法总结(03)_洛克家族的博客-CSDN博客_opencv puttext文章来源:https://www.toymoban.com/news/detail-432187.html
最后附上效果图:
文章来源地址https://www.toymoban.com/news/detail-432187.html
代码:
import cv2
import numpy as np
import os
from tqdm import tqdm
BLACK = [0, 0, 0]
GRAY = [135, 139, 142]
# Turn the large image into a small one, without changing the aspect ratio, and add black borders to make up for the
# shortage.
def my_resize(image, height, width):
h, w, c = image.shape
top, bottom, left, right = (0, 0, 0, 0)
# assert h >= height and w >= width, 'ratio should less than 1'
long_side = max(h, w)
if h >= w:
ratio = float(height) / long_side
elif h < w:
ratio = float(width) / long_side
# resize the long side and add black border to the both size of the short side
resi = cv2.resize(image, (0, 0), fx=ratio, fy=ratio, interpolation=cv2.INTER_NEAREST)
res_height, res_width, res_c = resi.shape
if h >= w:
if res_width < width:
dw = width - res_width
left = dw // 2
right = dw - left
elif h < w:
if res_height < height:
dh = height - res_height
top = dh // 2
bottom = dh - top
dst = cv2.copyMakeBorder(resi, top, bottom, left, right, cv2.BORDER_CONSTANT, value=BLACK)
return dst
def get_hms(seconds):
m, s = divmod(seconds, 60)
h, m = divmod(m, 60)
str = "%02d:%02d:%02d" % (h, m, s)
return str
def escribir_info(img, fname, infos = ()):
addtext = img.copy()
msg0 = 'File Name: ' + fname
msg1 = 'File Size: ' + str(infos[0]) + ' bytes (' + str(round(infos[0] / 1024.0 / 1024.0, 2)) + ' MB)'
msg2 = 'Resolution: ' + str(int(infos[2])) + 'x' + str(int(infos[1]))
msg3 = 'FPS: ' + str(round(infos[3], 2))
seconds = round(infos[4] / infos[3], 3)
msg4 = 'Duration: ' + get_hms(seconds) + ' (' + str(seconds) + ' s)'
cv2.putText(addtext, msg0, (20, 30), cv2.FONT_HERSHEY_COMPLEX, 1.0, (255, 255, 255), 2)
cv2.putText(addtext, msg1, (20, 70), cv2.FONT_HERSHEY_COMPLEX, 1.0, (255, 255, 255), 2)
cv2.putText(addtext, msg2, (20, 110), cv2.FONT_HERSHEY_COMPLEX, 1.0, (255, 255, 255), 2)
cv2.putText(addtext, msg3, (20, 150), cv2.FONT_HERSHEY_COMPLEX, 1.0, (255, 255, 255), 2)
cv2.putText(addtext, msg4, (20, 190), cv2.FONT_HERSHEY_COMPLEX, 1.0, (255, 255, 255), 2)
return addtext
def gen_captura(img_path, path_dir):
cap = cv2.VideoCapture(img_path)
frame_cnt = cap.get(cv2.CAP_PROP_FRAME_COUNT)
frame_itv = int(frame_cnt // 8) - 1 # 9 pictures
s_frame = 1
flag = 1
imgs = []
while cap.isOpened():
cap.set(cv2.CAP_PROP_POS_MSEC, flag)
cap.set(cv2.CAP_PROP_POS_FRAMES, s_frame)
ret, img = cap.read()
try:
dst = my_resize(img, 360, 640)
except Exception as e:
print('Error while capturing thumbnails: ' + str(e) + '\nNow we will use a black image to fill')
dst = np.zeros((360, 640, 3), np.uint8)
dst[:] = [0, 0, 0]
finally:
imgs.append(dst)
flag += 1
s_frame += frame_itv
if s_frame >= frame_cnt:
break
# Stitching images into a nine-box grid
img0 = np.concatenate(imgs[:3], 1)
img1 = np.concatenate(imgs[3:6], 1)
img2 = np.concatenate(imgs[6:], 1)
img9 = np.concatenate([img0, img1, img2], 0)
res = cv2.copyMakeBorder(img9, 200, 0, 0, 0, cv2.BORDER_CONSTANT, value=GRAY)
pint = os.path.basename(img_path)
res = escribir_info(res, pint, (os.path.getsize(img_path),
cap.get(cv2.CAP_PROP_FRAME_HEIGHT), cap.get(cv2.CAP_PROP_FRAME_WIDTH),
cap.get(cv2.CAP_PROP_FPS), cap.get(cv2.CAP_PROP_FRAME_COUNT)))
cv2.imwrite(os.path.join(path_dir, os.path.splitext(pint)[0] + '_scr.jpg'), res)
cap.release()
cv2.destroyAllWindows()
if __name__ == '__main__':
path_dir = input('Please input directory path that contains video:')
if not os.path.exists(path_dir):
print('Directory does not exist!')
exit(0)
proc_list = []
for r, d, files in os.walk(path_dir):
for file in files:
if file.endswith('mp4') or file.endswith('mkv') :
padre = os.path.join(r, file)
padre = padre.replace('\\', '/')
proc_list.append((padre, r))
for i, tp in tqdm(enumerate(proc_list)):
print('Now processing video: ' + tp[0])
gen_captura(tp[0], tp[1])
到了这里,关于OpenCV对指定目录下所有视频批量生成九宫格缩略图的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!