Flask+视频关键帧提取——媒体大数据实例分析


前言

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后,效果比前两者要好

步骤:

  1. 图片缩放,一般为88,或者3232(为了保留图像的结构,降低图像的信息量,需要去掉细节、大小和横纵比的差异,建议把图片统一缩放到8*8,共64个像素的图片)
  2. 将图片灰度化
  3. 求平均值,并根据平均值将每一个像素二值化(遍历灰度图片每一个像素,如果大于平均值记录为1,否则为0)
  4. 将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在效率几乎相同的情况下的效果要更好,它是基于渐变实现的。
步骤:

  1. 图片缩放为9*8大小
  2. 将图片灰度化
  3. 差异值计算(计算相邻像素间的差异值,这样每行9个像素之间产生了8个不同的差异,一共8行,则产生了64个差异值;前一个像素大于后一个像素则为1,否则为0)
  4. 生成哈希值

①获取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(离散余弦变换)来降低频率。

  1. 图片缩放 为32*32大小
  2. 将图片灰度化
  3. 对图片进行离散余弦变换(DCT),转换的频域
  4. 取频域左上角8*8大小(图片的能量都集中在低频部分,低频位于左上角)
  5. 计算平均值,并根据平均值二值化(同平均哈希)
  6. 生成哈希值

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

②使用汉明距离量化两张图像的相似性:

## 方法3:调用感知哈希算法,得到哈希值,计算汉明距离
        hash1 = pHash(frame0)
        hash2 = pHash(frame1)
        n3 = cmpHash(hash1, hash2)
        s = 1 - float(n3 / 64)

2-4. 三通道直方图算法

辅助理解
简单的理解:图像像素的统计分布,即像素值(0-255)之间的像素值,在一幅图像上的统计结果就是直方图。
①计算单通道:

# 灰度直方图算法
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(hist1[i] - hist2[i]) / max(hist1[i], hist2[i])) # abs绝对值
        else:
            degree = degree + 1
    degree = degree / len(hist1)
    return degree

②彩色图片拆分为RGB三通道,计算均值:

def classify_hist_with_split(image1, image2, size=(256, 256)):
    # RGB每个通道的
  • 1
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值