赞
踩
深度学习在数据准备准备方面,有时我们需要把一个长视频截取成一张张的图片,来扩充我们的数据量,但是在按照一定的帧率去截取图片试我们会发现有好多相似且重复的图片出现,但是我们增加训练样本时有需要样式不同风格不同角度不同的一系列的图片去扩充,这个时候就需要在视频截图过程中简单的去判断一下前后之前图片的相似程度
目录
简单的查阅资料以后发现有以下这几种简单的且快捷的算法可以比较图像之间的相似度
基于互信息(Mutual Information)计算图片的相似度
综合上面的比较方法,我最终选定的是差异值哈希+明汉距离算法,精确度较高,且速度也非常快,你们也可以试一试各个算法的效果比较实现代码都在上面可以直接运行
- from PIL import Image
- from numpy import average, dot, linalg
-
-
- def get_img(image, size=(64, 64)):
- # 利用image对图像大小重新设置, Image.ANTIALIAS为高质量的
- image = image.resize(size, Image.ANTIALIAS)
- # 将图片转换为L模式,其为灰度图,其每个像素用8个bit表示
- image = image.convert('L')
- return image
-
-
- # 计算图片的余弦距离
- def image_similarity(image1, image2):
- image1 = get_thum(image1)
- image2 = get_thum(image2)
- images = [image1, image2]
- vectors = []
- norms = []
- for image in images:
- vector = []
- for i in image.getdata():
- vector.append(average(i))
- vectors.append(vector)
- #2范数
- norms.append(linalg.norm(vector, 2))
- a, b = vectors
- a_norm, b_norm = norms
- # dot返回的是点积,对二维数组(矩阵)进行计算
- res = dot(a / a_norm, b / b_norm)
- return res
- import cv2
-
- def ahash(image):
- # 将图片缩放为8*8的
- image = cv2.resize(image, (8, 8), interpolation=cv2.INTER_CUBIC)
- # 将图片转化为灰度图
- gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
- # s为像素和初始灰度值,hash_str为哈希值初始值
- s = 0
- # 遍历像素累加和
- for i in range(8):
- for j in range(8):
- s = s + gray[i, j]
- # 计算像素平均值
- avg = s / 64
- # 灰度大于平均值为1相反为0,得到图片的平均哈希值,此时得到的hash值为64位的01字符串
- ahash_str = ''
- for i in range(8):
- for j in range(8):
- if gray[i, j] > avg:
- ahash_str = ahash_str + '1'
- else:
- ahash_str = ahash_str + '0'
- result = ''
- # 将上面的hash值转换为16位的
- for i in range(0, 64, 4):
- result += ''.join('%x' % int(ahash_str[i: i + 4], 2))
- # print("ahash值:",result)
- return result
感知哈希
- import cv2
- import numpy as np
-
- def phash(img):
- # 加载并调整图片为32*32的灰度图片
- img1 = cv2.resize(img, (32, 32),cv2.COLOR_RGB2GRAY)
- # 创建二维列表
- h, w = img.shape[:2]
- vis0 = np.zeros((h, w), np.float32)
- vis0[:h, :w] = img1
- # DCT二维变换
- """离散余弦变换(DCT)是种图像压缩算法,它将图像从像素域变换到频率域。然后一般图像都存在很多冗余和相关性的,所以转换到频率域之后,只有很少的一部分频率分量的系数才不为0,大部分系数都为0(或者说接近于0)。Phash哈希算法过于严格,不够精确,更适合搜索缩略图,为了获得更精确的结果可以选择感知哈希算法,它采用的是DCT(离散余弦变换)来降低频率的方法。"""
- # 离散余弦变换,得到dct系数矩阵
- img_dct = cv2.dct(cv2.dct(vis0))
- # 缩小DCT:DCT计算后的矩阵是32 * 32,保留左上角的8 * 8,这些代表的图片的最低频率
- img_dct.resize(8,8)
- # 把list变成一维list
- img_list = np.array().flatten(img_dct.tolist())
- # 计算均值
- img_mean = cv2.mean(img_list)
- # 进一步减小DCT:大于平均值记录为1,反之记录为0.
- avg_list = ['0' if i<img_mean else '1' for i in img_list]
- return ''.join(['%x' % int(''.join(avg_list[x:x+4]),2) for x in range(0,64,4)])
差值哈希
- import cv2
-
- def dHash(img):
- # 差值哈希算法
- # 先将图片压缩成9*8的小图,有72个像素点
- img = cv2.resize(img, (9, 8))
- # 转换灰度图
- gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
- # print(gray.shape)
- hash_str = ''
-
- # 计算差异值:dHash算法工作在相邻像素之间,这样每行9个像素之间产生了8个不同的差异,一共8行,则产生了64个差异值,或者是32位01字符串
- 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
汉明距离计
- def cmpHash(hash1, hash2):
- # Hash值对比
- # 算法中1和0顺序组合起来的即是图片的指纹hash。顺序不固定,但是比较的时候必须是相同的顺序。
- # 对比两幅图的指纹,计算汉明距离,即两个64位的hash值有多少是不一样的,不同的位数越小,图片越相似
- # 汉明距离:一组二进制数据变成另一组数据所需要的步骤,可以衡量两图的差异,汉明距离越小,则相似度越高。汉明距离为0,即两张图片完全一样
- 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
'运行
- import cv2
-
- # 直方图计算相似度
- def calc_similar(img1, img2):
- # 计算图img的直方图
- H1 = cv2.calcHist([img1], [1], None, [256], [0, 256])
- # 对图片进行归一化处理
- H1 = cv2.normalize(H1, H1, 0, 1, cv2.NORM_MINMAX, -1)
- # 计算图img2的直方图
- H2 = cv2.calcHist([img2], [1], None, [256], [0, 256])
- # 对图片进行归一化处理
- H2 = cv2.normalize(H2, H2, 0, 1, cv2.NORM_MINMAX, -1)
- # 利用compareHist()进行比较相似度
- similarity = cv2.compareHist(H1, H2, 0)
- return similarity
- from skimage.measure import compare_ssim
- from scipy.misc import imread
- import numpy as np
- # 读取图片
- img1 = imread('1.jpg')
- img2 = imread('2.jpg')
- # 使得两图片大小相等
- img2 = np.resize(img2, (img1.shape[0], img1.shape[1], img1.shape[2]))
- ssim = compare_ssim(img1, img2, multichannel = True)
- from sklearn import metrics as mr
- from scipy.misc import imread
- import numpy as np
-
- img1 = imread('1.jpg')
- img2 = imread('2.jpg')
- # 使得两图片大小相等
- img2 = np.resize(img2, (img1.shape[0], img1.shape[1], img1.shape[2]))
-
- img1 = np.reshape(img1, -1)
- img2 = np.reshape(img2, -1)
- mutual_infor = mr.mutual_info_score(img1, img2)
- cv2.CAP_PROP_POS_MSEC 0 视频文件的当前位置(以毫秒为单位)或视频捕获时间戳
- cv2.CAP_PROP_POS_FRAMES 1 基于0的索引将被解码/捕获下一帧
- cv2.CAP_PROP_POS_AVI_RATIO 2 视频文件的相对位置:0 - 视频的开始,1 - 视频的结束
- cv2.CAP_PROP_FRAME_WIDTH 3 帧的宽度
- cv2.CAP_PROP_FRAME_HEIGHT 4 帧的高度
- cv2.CAP_PROP_FPS 5 帧速
- cv2.CAP_PROP_FOURCC 6 4个字符表示的视频编码器格式
- cv2.CAP_PROP_FRAME_COUNT 7 帧数
- cv2.CAP_PROP_FORMAT 8 byretrieve()返回的Mat对象的格式
- cv2.CAP_PROP_MODE 9 指示当前捕获模式的后端特定值
- cv2.CAP_PROP_BRIGHTNESS 10 图像的亮度(仅适用于相机)
- cv2.CAP_PROP_CONTRAST 11 图像对比度(仅适用于相机)
- cv2.CAP_PROP_SATURATION 12 图像的饱和度(仅适用于相机)
- cv2.CAP_PROP_HUE 13 图像的色相(仅适用于相机)
- cv2.CAP_PROP_GAIN 14 图像的增益(仅适用于相机)
- cv2.CAP_PROP_EXPOSURE 15 曝光(仅适用于相机)
- cv2.CAP_PROP_CONVERT_RGB 16 表示图像是否应转换为RGB的布尔标志
- import cv2
-
- def cmpHash(hash1, hash2):
- n = 0
- if len(hash1) != len(hash2):
- return -1
- for i in range(len(hash1)):
- if hash1[i] != hash2[i]:
- n = n + 1
- return n
-
-
- def dHash(img):
- img = cv2.resize(img, (9, 8))
- gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
- 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
-
-
-
- def get_fraem(file_path):
- # file_path是文件的绝对路径,防止路径中含有中文时报错,需要解码
- cap = cv2.VideoCapture(file_path)
- # 记录前后图片的地址
- dict_img = {"1": [], }
- # 每隔多少帧获取一张图片
- img_fream = 60
- # 差异值
- img_dif = 20
- if cap.isOpened(): # 当成功打开视频时cap.isOpened()返回True,否则返回False
- rate = int(cap.get(5)) # 帧速率
- FrameNumber = cap.get(7) # 视频文件的帧数
- # duration = FrameNumber/rate/60 # 帧速率/视频总帧数 是时间,除以60之后单位是分钟
- # timeF = int(FrameNumber // rate) # 每秒获取1张图片
- timeF = int(FrameNumber // img_fream)
- print(rate)
- print(timeF)
- print(FrameNumber)
- c = 1
- while True:
- sm_img = 0
- # 视频读取完毕退出
- if c > timeF * rate + 1:
- print('######################')
- break
- # 视频读取完毕退出
- if c > FrameNumber:
- print('******************')
- break
- # 读取当前帧数图片
- success, frame = cap.read()
- # 帧数到你需要截取的帧数时
- if c % rate == 0:
- # 记录上一张图片和当前图片
- if "2" in dict_img:
- # 计算图片的差异值哈希
- dict_img["1"] = dict_img["2"]
- else:
- dict_img["1"] =dHash(frame)
- # 计算图片的差异值哈希
- dict_img["2"] = dHash(frame)
- # 明汉距离计算差异值
- sm_img = cmpHash(dict_img["1"], dict_img["2"])
-
- if sm_img:
- # 当差异值不为0且大于我们预设的阈值的时候打印当前帧数并且保存图片
- if sm_img >=img_dif:
- cv2.imwrite('img/{}.jpg'.format(c), frame)
- print(c)
- c += 1
- if not success:
- print('video is all read')
- break
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。