任务

在Windows10系统下,用python,在jupyter notebook,对week5中“将视频每一帧保存成图像”的基础上,通过自定义的均值哈希算法、各通道直方图两种方法对该有序系列图片进行相似度计算,拣出差距大于一定值的图片另存,以判断原视频的镜头数。

应用ffmpeg在长视频中截取片段,转换为图像,估计镜头数。

Ⅰ均值哈希算法

导入所需各库。

os和shutil两个库用来相互辅助完成新建、删除、遍历文件或文件夹的功能。

os.remove(r"里面填文件路径"):删文件(慎用,错了该文件就找不回来了)
os.makedirs("./p"):当前工作路径下新建文件夹p
os.listdir("./p"):遍历p文件夹内的文件,返回内含文件夹内各文件的列表      os.removedirs("./p"):当前工作路径下删除空文件夹p(文件夹必须为空,否则报错)
shutil.rmtree("./p",ignore_errors=True)#删除文件夹,非空也能删除

import cv2
import numpy as np
import matplotlib.pyplot as plt
from PIL import Image
import inspect
import os
import shutil

定义函数,转换图像表达式:

更改图片规格为8*8,转为灰度图像

遍历图片8*8每个格子,并叠加每个格子的像素,求其均值

遍历图片8*8每个格子,并判断像素值与均值的大小,大于均值返回1,小于均值返回0,最后得到一个64位的二进制数

彩色图像img[i,j,c]:i表示图片的行数,j表示图片的列数,c表示图片的通道数(RGB三通道分别对应0,1,2)。坐标是从左上角开始。

灰度图像gray[i,j]:返回图像第i行第j列的像素值

def aHash(img):#缩放为8x8"""plt.imshow(img)plt.axis("off")plt.show()"""img=cv2.resize(img,(8,8))"""plt.imshow(img)plt.axis("off")plt.show()"""#转换为灰度图gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)#s为像素和初值为0,hash _str为hash 值初值为''s=0hash_str=""#遍历累加求像素和for i in range(8):for j in range(8):s=s+gray[i,j]#求灰度平均avg=s/64#灰度大于平均值为1相反为0生成图片的hash值for i in range(8):for j in range(8):if gray[i,j]>avg:hash_str=hash_str+"1"else:hash_str=hash_str+"0"return hash_str

定义函数,比较两个图像表达式的区别,并得出图像差别大小,返回值gap越大,差别越大

if语句,若两图hash长度不同,返回-1表示传参出错

for循环,遍历两张图像64位二进制数每一位,判断其区别,若不同,则gap+1,表示差别更大

def cmpHash(hash1,hash2):gap=0#hash长度不同则返回-1代表传参出错if len(hash1)!=len(hash2):return -1for i in range(len(hash1)):if hash1[i]!=hash2[i]:gap=gap+1return gap

删除当前工作路径下名为p的文件夹并生成一个空文件夹p,以防同段代码多次运行导致文件夹内文件混乱

遍历保存了有序系列图像的文件夹pic

将文件夹pic中第一张图片同名保存至文件夹p

shutil.rmtree("./p",ignore_errors=True)
os.makedirs("./p")
filelist=os.listdir("./pic")
cv2.imwrite(os.path.join("./p",filelist[0]),img1)

方法1:遍历比较时不是相邻两张图片比较,而是相邻两张显示足够相似时,左图不变,右图从第一张图开始遍历,比较两张图,直到相似度过低时,保存右图,并将当前右图更换为左图,而右图继续遍历,直至遍历结束。

for i in range(len(filelist)-1):img2=cv2.imread("./pic/"+"image{}".format(i+1)+".jpg")gap=cmpHash(aHash(img1),aHash(img2))if gap>35:cv2.imwrite(os.path.join("./p","image{}".format(i+1)+".jpg"),img2)img1_name="image{}".format(i+1)img1=cv2.imread("./pic/"+"image{}".format(i+1)+".jpg")

运行结果:

方法2:遍历图片,每次都比较相邻两张图片,若差别过大,则保存右图

for i in range(len(filelist)-1):img1=cv2.imread("./pic/image{}.jpg".format(i))img2=cv2.imread("./pic/image{}.jpg".format(i+1))gap=cmpHash(aHash(img1),aHash(img2))if gap>23:cv2.imwrite(os.path.join("./p/image{}.jpg".format(i+1)),img2)  

运行结果:

两种判断方法,从实践情况来看,前者的不稳定性更强,被认定的镜头数量(即保存的图片数量)不完全随着所设定的gap临界值增大而减少,且当前后两者保存的图片数量接近时,往往前者的gap临界值更大

完整代码:

import cv2
import numpy as np
import matplotlib.pyplot as plt
from PIL import Image
import os
import inspect
import shutildef aHash(img):img=cv2.resize(img,(8,8))gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)s=0hash_str=""for i in range(8):for j in range(8):s=s+gray[i,j]avg=s/64for i in range(8):for j in range(8):if gray[i,j]>avg:hash_str=hash_str+"1"else:hash_str=hash_str+"0"return hash_strdef cmpHash(hash1,hash2):gap=0if len(hash1)!=len(hash2):return -1for i in range(len(hash1)):if hash1[i]!=hash2[i]:gap=gap+1return gapshutil.rmtree("./p",ignore_errors=True)
os.makedirs("./p")
filelist=os.listdir("./pic")
cv2.imwrite(os.path.join("./p",filelist[0]),img1)"""for i in range(len(filelist)-1):img2=cv2.imread("./pic/"+"image{}".format(i+1)+".jpg")gap=cmpHash(aHash(img1),aHash(img2))if gap>35:cv2.imwrite(os.path.join("./p","image{}".format(i+1)+".jpg"),img2)img1_name="image{}".format(i+1)img1=cv2.imread("./pic/"+"image{}".format(i+1)+".jpg")""" for i in range(len(filelist)-1):img1=cv2.imread("./pic/image{}.jpg".format(i))img2=cv2.imread("./pic/image{}.jpg".format(i+1))gap=cmpHash(aHash(img1),aHash(img2))if gap>23:cv2.imwrite(os.path.join("./p/image{}.jpg".format(i+1)),img2)   

Ⅱ各通道直方图相似度计算

导入所需各库

import cv2
import numpy as np
import matplotlib.pyplot as plt
import os
import shutil

定义函数,更改图像规格,并将RGB三通道分离

zip() 函数用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的列表。

cv2.split():拆分通道,输入图像矩阵array,输出拆分成每个点按照颜色为BGR顺序的三维矩阵array

cv2.merge():合并通道

calculate(a,b)为后面定义的函数,计算各通道直方图重合度,值越大,重合度越高

各通道重合度求均值,得出完整的相似度

def classify_hist_with_split(image1,image2,size=(256, 256)):# 将图像resize后,分离为RGB三个通道,再计算每个通道的相似值image1=cv2.resize(image1,size)image2=cv2.resize(image2,size)
#     plt.imshow(image1)
#     plt.show()
#     plt.axis('off')#     plt.imshow(image2)
#     plt.show()
#     plt.axis('off')sub_image1=cv2.split(image1)sub_image2=cv2.split(image2)sub_data=0for im1,im2 in zip(sub_image1,sub_image2):sub_data+=calculate(im1,im2)sub_data=sub_data/3return sub_data

定义函数,计算单通道的直方图的相似值

cv2.calcHist(images, channels, mask, histSize, ranges[, hist[, accumulate]]) -> hist imaes:输入的图像
channels:选择图像的色彩通道
mask:掩膜(遮罩、蒙版),是一个大小和image一样的np数组,其中把需要处理的部分指定为1,不需要处理的部分指定为0,一般设置为None,表示处理整幅图像
histSize:使用多少个bin(柱子),一般为256
ranges:像素值的范围,一般为[0,255]表示0~255

abs():返回绝对值

def calculate(image1, image2):hist1=cv2.calcHist([image1],[0],None,[256],[0.0,255.0])hist2=cv2.calcHist([image2],[0],None,[256],[0.0,255.0])
#     plt.plot(hist1,color="r")
#     plt.plot(hist2,color="g")
#     plt.show()# 计算直方图的重合度degree=0for i in range(len(hist1)):if hist1[i]!=hist2[i]:degree=degree+(1-abs(hist1[i]-hist2[i])/max(hist1[i],hist2[i]))else:degree=degree+1    #统计相似degree=degree/len(hist1)return degree

与均值哈希算法相似的两种实操方法

filelist=os.listdir("./pic")
print(type(filelist))
print(len(filelist))
shutil.rmtree("./pp",ignore_errors=True)#删除文件夹,非空文件夹也可以
os.makedirs("./pp")
a=range(len(filelist)-1)
cv2.imwrite(os.path.join("./pp",filelist[0]),img1)"""#遍历比较时不是相邻两张图片比较,而是相邻两张显示足够相似时,第一张图不变,第二张图顺延,这两张图继续比较
for i in a:img2=cv2.imread("./pic/"+"image{}".format(i+1)+".jpg")#print(img1_name,"image{}".format(i+1),sep=",")n=classify_hist_with_split(img1, img2)#print(n)if n<0.42:cv2.imwrite(os.path.join("./pp","image{}".format(i+1)+".jpg"),img2)#img1_name="image{}".format(i+1)img1=cv2.imread("./pic/"+"image{}".format(i+1)+".jpg")"""for i in a:img1=cv2.imread("./pic/image{}.jpg".format(i))img2=cv2.imread("./pic/image{}.jpg".format(i+1))n=classify_hist_with_split(img1, img2)if n<0.55:cv2.imwrite(os.path.join("./pp/image{}.jpg".format(i+1)),img2)

值得注意的是:均值哈希算法的结果,gap越大,差距越大;直方图相似度的结果,n越大,相似度越大,差距越小。两种算法的结果数值范围也不相同,前者为≥1整数级,后者为≤1小数级。

Ⅲffmpeg截取视频片段

在ffmpeg程序所在目录下打开命令提示符cmd输入如下代码(两段代码截取两段视频):

-i 输入路径

-ss 起始时间

-t 持续时间(注意:非结束时间)

输出的路径直接写就行,没有-和某字母做开头

ffmpeg -i G:/vip电影/让子弹飞/让子弹飞.mp4 -ss 01:54:17 -t 00:00:18 G:/大三上/各门课作业/python/week6/out1.mp4
ffmpeg -i G:/vip电影/让子弹飞/让子弹飞.mp4 -ss 01:18:00 -t 00:00:18 G:/大三上/各门课作业/python/week6/out2.mp4

视频截好后在命令提示符中输入如下代码:

将两个视频每一帧转成图像,并按照名为image1、image2……的顺序(注意:第一张图片不是image0)

此处没有写绝对路径的原因是,ffmpeg程序位置和out1、out2文件夹在同一个目录下(这两个文件夹须提前新建,ffmpeg不提供自动新建功能,它只报错)

ffmpeg -i out2.mp4 -r 10 -f image2 out2/image%d.jpg
ffmpeg -i out1.mp4 -r 10 -f image2 out1/image%d.jpg

两个视频内容不同,后续处理逻辑相同,故以out1做示范。

系列图片命名从image1开始,与前面写好的代码默认从image0开始不同,可修改系列图片命名以便运行,可选择修改前面的代码,此处以修改图片命名为例。

filelist=os.listdir("./out1")
for i in range(len(filelist)):infile="./out1/image{}.jpg".format(i+1)outfile="./out1/image{}.jpg".format(i)Image.open(infile).save(outfile)os.remove(infile)

完整代码:

#均值哈希算法、各通道直方图比较相似度,加上系列文件重命名
import cv2
import numpy as np
import matplotlib.pyplot as plt
import os
import shutil
#均值哈希算法
def aHash(img):img=cv2.resize(img,(8,8))gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)s=0hash_str=""for i in range(8):for j in range(8):s=s+gray[i,j]avg=s/64for i in range(8):for j in range(8):if gray[i,j]>avg:hash_str=hash_str+"1"else:hash_str=hash_str+"0"return hash_str
def cmpHash(hash1,hash2):n=0if len(hash1)!=len(hash2):return -1for i in range(len(hash1)):if hash1[i]!=hash2[i]:n=n+1return n
# 通过得到RGB每个通道的直方图来计算相似度
def classify_hist_with_split(image1,image2,size=(256, 256)):# 将图像resize后,分离为RGB三个通道,再计算每个通道的相似值image1=cv2.resize(image1,size)image2=cv2.resize(image2,size)   sub_image1=cv2.split(image1)sub_image2=cv2.split(image2)sub_data=0  for im1,im2 in zip(sub_image1,sub_image2):sub_data+=calculate(im1,im2)sub_data=sub_data/3return sub_data
# 计算单通道的直方图的相似值
def calculate(image1, image2):hist1=cv2.calcHist([image1],[0],None,[256],[0,255])hist2=cv2.calcHist([image2],[0],None,[256],[0,255])# 计算直方图的重合度degree=0for i in range(len(hist1)):if hist1[i]!=hist2[i]:degree=degree+(1-abs(hist1[i]-hist2[i])/max(hist1[i],hist2[i]))else:degree=degree+1    #统计相似degree=degree/len(hist1)return degree
#重命名系列文件,本来从image1开始,现改为从image0开始
filelist=os.listdir("./out1")
for i in range(len(filelist)):infile="./out1/image{}.jpg".format(i+1)outfile="./out1/image{}.jpg".format(i)Image.open(infile).save(outfile)os.remove(infile)
shutil.rmtree("./out1p",ignore_errors=True)
os.makedirs("./out1p")
cv2.imwrite(os.path.join("./out1p/image0.jpg"),cv2.imread("./out1/image0.jpg"))
#均值哈希算法实操结果
for i in range(len(filelist)-1):img1=cv2.imread("./out1/image{}.jpg".format(i))img2=cv2.imread("./out1/image{}.jpg".format(i+1))gap=cmpHash(aHash(img1),aHash(img2))if gap>30:cv2.imwrite(os.path.join("./out1p/image{}.jpg".format(i+1)),img2)
#各通道直方图计算相似度的实操结果
shutil.rmtree("./out1pp",ignore_errors=True)
os.makedirs("./out1pp")
cv2.imwrite(os.path.join("./out1pp/image0.jpg"),cv2.imread("./out1/image0.jpg"))
for i in range(len(filelist)-1):img1=cv2.imread("./out1/image{}.jpg".format(i))img2=cv2.imread("./out1/image{}.jpg".format(i+1))n=classify_hist_with_split(img1, img2)if n<0.55:cv2.imwrite(os.path.join("./out1pp/image{}.jpg".format(i+1)),img2)

运行结果:

均值哈希算法:

各通道直方图:

Ⅳ代码bug

1.采用非相邻两图片判断相似度时,结果虽然不会报错,但保存的图片一直很混乱。

右图一直是按顺序遍历,但显示结果却时1,10,100,101...109,11,110,111,可见遍历顺序的逻辑不是数值大小,而是在判断ASCII码的大小

for i in range(len(filelist)-1)遍历,理论上是按照尾数从小到大的顺序即image0 image1 image2,但实际上顺序并非如此

查看filelist:

故而后续不再使用filelist[i]的索引,而采用image{}.jpg".format(i)

week6 视频分镜相关推荐

  1. #计算机视频处理 使用ffmpeg对视频进行操作、视频分镜

    参考文档: 官网 音视频处理工具ffmpeg ffmpeg官方文档 音视频合成分割 基本用法 ffmpeg 处理视频音频 转化方式 编码 转化格式 ffmpeg -i out.mp4 -vcodec ...

  2. 利用pycharm进行视频分镜处理

    一.Hi,Flask! 在pycharm里创建新文件,命名为main.py from flask import Flask,render_template app=Flask(__name__) #_ ...

  3. Python软件设计基础 第五节-基于图像相似度比较实现视频分镜

    目录 一.前言 一.基础算法-判断两张图片是否相等/相似 (一)基于相等判断图像是否相同 (二)基于numpy计算图像是否相似 (三)基于哈希判断图像是否相似 (四)基于各种哈希计算图片相似度 1.均 ...

  4. 课5 视频分镜的处理

    一.对视频进行处理,分解成一帧一帧的图片保存到一个新建的文件夹: import os import cv2 import subprocessv_path='lulu.mp4' image_save= ...

  5. 利用Python视频处理分镜——FFmpeg、OpenCV

    一.视频处理的简单命令 视频处理的思路是先将视频分解成一帧一帧的图像,对每一帧进行处理,处理好后再将帧合并为视频.会用到的模块包括OpenCV.FFmpeg等. OpenCV:强大的计算机视觉库,可以 ...

  6. Python视频处理(2)——Flask网页开发+分镜

    目录 一.主程序基本结构 1.安装并导入Flask 2.创建Flask对象(很重要的一步,不能忘记) 3.编写主程序 4.路由 5.完整代码 二.渲染网页 三.定义分镜相关函数 1.定义切帧函数并调用 ...

  7. 短视频自导自演,分镜脚本如何设计

    前言: 在进入主题之前我先强调一下,这篇完全是番外,小编的主线还是以编码类为重的文章.至于原因有两点,一是距离上次更新到现在已经快一个月,所以先总结一下近期玩的东西补上.二是我确实正在再次尝试做短视频 ...

  8. 帮我写8寸循环风扇分镜,需要宣传台面地面2合1 两用,循环吹风,材质肤感高级,多模式选择,上下左右摇头,做成45秒视频10个分镜脚本,并写出这10个镜头之间转场如何运镜...

    分镜脚本: 镜头1:开场镜头,展示循环风扇外观.材质和特点.持续时间:5秒. 镜头2:展示风扇的多模式选择,可以在多种风力模式中自由选择.持续时间:3秒. 镜头3:展示风扇上下左右摇头的功能.持续时间 ...

  9. html5中分镜图文脚本,抖音分镜脚本这样做 轻松打造100w+粉丝大号

    分镜头脚本是创作者必不可少的前期准备,也是演员和所有创作人员领会导演意图,理解剧本内容的重要依据. 那么抖音分镜头脚本怎么创作呢?分镜头脚本模板哪里有? 抖音分镜头脚本怎么写 分镜头脚本适合故事性较强 ...

最新文章

  1. solr kerberos java_solr添加kerberos认证及授权
  2. 部署go的web应用_使用Docker部署Go Web应用
  3. DedeCMS Wap.php绑定域名的方法
  4. c# unchecked关键字。byte 合并short
  5. CUDA性能优化----线程配置
  6. centos7查看当前端口_Centos7 防火墙开放端口,查看状态,查看开放端口
  7. [C]Ubuntu 13.04实现NVIDIA双显卡切换
  8. 1436. 旅行终点站
  9. 使用 React和webpack开发和打包发布
  10. 机器学习--逻辑斯谛回归(Logistic Regression)
  11. Linux设备树OF API 中OF的含义
  12. 局域网远程控制工具之VNC
  13. 【IPTV】华为IPTV解决方案总体介绍
  14. mysql中文模糊查询_解决mysql中文模糊查询问题的方法
  15. 机器学习实战(第1章)
  16. 计算机视觉论文-2021-07-19
  17. 如何通过Matplotlib画圆
  18. pdfjs转图片_Vue项目pdf(base64)转图片
  19. 小程序map组件一——使用腾讯地图个性化地图组件、腾讯云可视化大屏展示
  20. zabbix 监控过程详解

热门文章

  1. 转:以独立之心,做合群之事
  2. 有理样条曲线学习笔记(一)
  3. linux . 乱码,解决Linux乱码现象
  4. Firefox如何给页面权限
  5. TGRS2022/遥感:An Empirical Study of Remote Sensing Pretraining遥感预训练的实证研究
  6. element ui 组件vue组件使用slot-scope=“scop“根据ID改变地址
  7. MybatisPlus中乐观锁的配置
  8. 科技感十足的数码首图海报
  9. java线程池newfi_Java进阶——线程与多线程
  10. download sources报错: Cannot connect to the Maven process. Try again later. If the problem persists