前言
1.编写目的
一方面是分享思路(啥都搜不到真的好痛苦)
另一方面是记录一下,方便自己以后查(感谢提供资料的师哥师姐们和老师)
2.实验环境
操作系统:Win10
IDE:PyCharm 2021.3 (Community Edition)
Python:3.8
3.实现内容
获取用户上传的视频,逐帧分析视频,分别使用均值哈希算法(ahash)、差值哈希算法(dhash)、感知哈希算法(phash)、三通道直方图算法(classify_hist_with_split)计算相邻帧的图片相似度,通过与阈值相比较提取视频分镜头关键帧,并通过flask将结果展示在网页上。
一、基础代码
1. 视频帧分割、保存
import cv2
video_path="static/video/ghz.mp4"
image_save="per_frame/"
cap=cv2.VideoCapture(video_path) # VideoCapture()中参数是0表示打开笔记本的内置摄像头;参数是视频文件路径则打开
video_frame_count=cap.get(cv2.CAP_PROP_FRAME_COUNT) # 视频帧数
for i in range(int(video_frame_count)):
# 按帧读取视频
ret,frame=cap.read() # cap.read()按帧读取视频;ret为True 或者False代表有没有读取到图片;frame就是每一帧的图像,是个三维矩阵。
# 图片转灰度
frame=cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY) # 使用opencv中cv2.cvtColor()函数来改变图像的颜色空间
# 保存
cv2.imwrite('per_frame/image{}.jpg'.format(i),frame)
2. 图片相似度计算
2-0.基于相等判断图像是否相同
import operator
from PIL import Image
import os
os.chdir('e:\mediabigdata')
a=Image.open('./img/image0.jpg')
b=Image.open('./img/image0.jpg')
out=operator.eq(a,b)
print(out)
2-0.基于numpy计算图像是否相似
import numpy as np
from PIL import Image
import os
os.chdir('e:\mediabigdata')
a=Image.open('./img/image0.jpg')
b=Image.open('./img/image0.jpg')
diff=np.subtract(a,b)
out=not np.any(diff)
print(out)
2-1. 均值哈希算法
aHash速度较快,但精确度较低;pHash则反其道而行之,精确度较高但速度较慢;dHash兼顾二者,精确度较高且速度较快。
1.均值哈希和差值哈希算法的时间都比感知哈希少,因为感知哈希resize为32*32,并且要进行DCT离散余弦变换,这个计算比较耗时
2.改变图片的亮度,色度,对比度,锐度,均值哈希的效果都是最好的,几乎不受影响,其次是差值哈希,最差是感知哈希
3.但是感知哈希在图片旋转以及resize后,效果比前两者要好
步骤:
- 图片缩放,一般为88,或者3232(为了保留图像的结构,降低图像的信息量,需要去掉细节、大小和横纵比的差异,建议把图片统一缩放到8*8,共64个像素的图片)
- 将图片灰度化
- 求平均值,并根据平均值将每一个像素二值化(遍历灰度图片每一个像素,如果大于平均值记录为1,否则为0)
- 将8*8=64位bit,每8个比特为一个十六进制值,转换成字符串,生成哈希值(指纹)
①获取hash值:
# 均值哈希算法
def aHash(img):
# 缩放为8*8
img = cv2.resize(img, (8, 8))
# 转换为灰度图
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# s为像素和初值为0,hash_str为hash值初值为''
s = 0
hash_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
②计算汉明距离:
生成每一个图片的哈希值后,需要计算哈希值的距离,来判断两张图片的相似度。一般使用汉明距离,也就是逐位计算两张图片的哈希值是否相同。
算法中1和0顺序组合起来的即是图片的指纹hash。顺序不固定,但是比较的时候必须是相同的顺序。
对比两幅图的指纹,计算汉明距离,即两个64位的hash值有多少是不一样的,不同的位数越小,图片越相似
汉明距离:一组二进制数据变成另一组数据所需要的步骤,可以衡量两图的差异,汉明距离越小,则相似度越高。汉明距离为0,即两张图片完全一样
# Hash值对比,计算汉明距离
def cmpHash(hash1, hash2):
n = 0
# hash长度不同,则返回-1代表传参出错
if len(hash1) != len(hash2):
return -1
# 遍历判断
for i in range(len(hash1)):
# 不相等则n计数+1,n最终为相似度
if hash1[i] != hash2[i]:
n = n + 1
return n # 返回汉明距离
③使用汉明距离量化两张图像的相似性:
## 方法1:调用均值哈希算法,得到哈希值,计算汉明距离
hash1 = aHash(frame0)
hash2 = aHash(frame1)
n1 = cmpHash(hash1, hash2) # 汉明距离
s = 1 - float(n1 / 64) # 得到一个不大于1的数值,值越大图片相似度越高
2-2. 差值哈希算法
相比pHash,dHash的速度更快,相比aHash,dHash在效率几乎相同的情况下的效果要更好,它是基于渐变实现的。
步骤:
- 图片缩放为9*8大小
- 将图片灰度化
- 差异值计算(计算相邻像素间的差异值,这样每行9个像素之间产生了8个不同的差异,一共8行,则产生了64个差异值;前一个像素大于后一个像素则为1,否则为0)
- 生成哈希值
①获取hash值:
# 差值哈希算法
def dHash(img):
# 缩放9*8
img = cv2.resize(img, (9, 8))
# 转换灰度图
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
hash_str = ''
# 每行前一个像素大于后一个像素为1,相反为0,生成哈希
for i in range(8):
for j in range(8):
if gray[i, j] > gray[i, j + 1]:
hash_str = hash_str + '1'
else:
hash_str = hash_str + '0'
return hash_str
②使用汉明距离量化两张图像的相似性:
## 方法2:调用差值哈希算法,得到哈希值,计算汉明距离
hash1 = dHash(frame0)
hash2 = dHash(frame1)
n2 = cmpHash(hash1, hash2)
s = 1 - float(n2 / 64)
2-3. 感知哈希算法
感知哈希算法可以获得更精确的结果,它采用的是DCT(离散余弦变换)来降低频率。
- 图片缩放 为32*32大小
- 将图片灰度化
- 对图片进行离散余弦变换(DCT),转换的频域
- 取频域左上角8*8大小(图片的能量都集中在低频部分,低频位于左上角)
- 计算平均值,并根据平均值二值化(同平均哈希)
- 生成哈希值
DCT变换的全称是离散余弦变换(Discrete Cosine Transform),主要用于将数据或图像的压缩,能够将空域的信号转换到频域上,具有良好的去相关性的性能。DCT变换本身是无损的,但是在图像编码等领域给接下来的量化、哈弗曼编码等创造了很好的条件,同时,由于DCT变换时对称的,所以,我们可以在量化编码后利用DCT反变换,在接收端恢复原始的图像信息。对原始图像进行离散余弦变换,变换后DCT系数能量主要集中在左上角,其余大部分系数接近于零,DCT具有适用于图像压缩的特性。将变换后的DCT系数进行门限操作,将小于一定值得系数归零,这就是图像压缩中的量化过程,然后进行逆DCT运算,可以得到压缩后的图像。
①获取hash值:
# 感知哈希算法
def pHash(img):
# 缩放32*32
img = cv2.resize(img, (32, 32)) # , interpolation=cv2.INTER_CUBIC # 指定图像缩放之后,重新计算像素的方式,默认是INTER_LINEAR
# 转换为灰度图
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 将灰度图转为浮点型,再进行dct变换
dct = cv2.dct(np.float32(gray)) # 计算DCT: DCT把图片分离成分率的集合;dct输入必须为单通道浮点型
# opencv实现的掩码操作
dct_roi = dct[0:8, 0:8] # DCT计算后的矩阵是32 * 32,保留左上角的8 * 8,这些代表的图片的最低频率
hash = []
avreage = np.mean(dct_roi) # 求均值,返回一个实数
for i in range(dct_roi.shape[0]):
for j in range(dct_roi.shape[1]):
if dct_roi[i, j] > avreage:
hash.append(1)
else:
hash.append(0)
return hash
②使用汉明距离量化两张图像的相似性:文章来源:https://www.toymoban.com/news/detail-429148.html
## 方法3:调用感知哈希算法,得到哈希值,计算汉明距离
hash1 = pHash(frame0)
hash2 = pHash(frame1)
n3 = cmpHash(hash1, hash2)
s = 1 - float(n3 / 64)
2-4. 三通道直方图算法
辅助理解
简单的理解:图像像素的统计分布,即像素值(0-255)之间的像素值,在一幅图像上的统计结果就是直方图。
①计算单通道:文章来源地址https://www.toymoban.com/news/detail-429148.html
# 灰度直方图算法
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])
# 计算直方图的重合度
degree = 0
for i in range(len(hist1)):
if hist1[i] != hist2[i]:
degree = degree + \
(1 - abs(his
到了这里,关于Flask+视频关键帧提取——媒体大数据实例分析的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!