缘起

Android上硬件编解码一直是个老大难问题,就解码来说,硬解码本身并不困难,只要按照MediaCodec的流程开发即可。但由于系统碎片化,硬件规格不一致,硬件解码会到黑屏,花屏,绿屏之类的显示问题。为了不招致用户投诉,我们在做视频解码的时候不太敢开启硬件加速,一般会采用保守策略,即以软解为主,优先保证画面正常,但牺牲了性能。

一般解决这个问题的方案是使用黑(白)机型名单下发配置(如:腾讯视频),或者暴露开关让用户手动去控制是否走硬件解码(如:bilibili)。

使用机型黑(白)名单有一定的作用,但其问题也显而易见:

  • 需要浪费大量的人力,精力进行机型测试,去维护,发布名单
  • 覆盖度偏低,一般只覆盖TOP机型
  • 缺乏时效性,例如新机型上市不能及时跟进
  • 不一定准确,因为硬解是否成功,跟视频源也有很大关系,同一个机型可能解这个视频不成功,另外一个视频又是成功的。按照机型\u0026quot;一刀切\u0026quot;的前提是要保证视频规格一致,这样才最健壮。

通过开关让用户切换体验太差,尤其是“抖音”之类的短视频App,总不能每个界面加个开关让用户去切换解码器这么深奥的东西吧,从用户角度讲,我为什么要关心这个什么解码器怎么设置,只要视频能正常看就行。

仔细思考一下,我们其实可以实现自动化的检测,即模拟人工检测流程,把样本视频各软硬解一遍,然后对比他们的解码结果(图片)就能够知道硬解码是否能跑通。解码的流程轻车熟路,那么这里的关键问题就是我们如何进行图片对比?如何量化图片的差异度?

图片检索技术

图片对比其实跟\u0026quot;以图搜图\u0026quot;本质上是同一种技术,通常有几种做法MSE,均值哈希,色彩直方图以及OpenCV里面一些提取图像特征的高级算法,如Sift,Surf等。基于移动端的运行效率,安装包大小,以及需求本身考虑,我们放弃引入OpenCV。MSE 属于逐像素对比,对像素值要求过于严格,太简单粗暴,色彩直方图不太好量化差异度。基于以上考虑,我们选择图像哈希算法,它可以输出汉明距离,方便量化软硬解结果的差异度。

哈希算法有三种,平均哈希,感知哈希和差异度哈希,基于准确度考虑,我们选择实现较复杂一些的感知哈希算法。另基于性能考虑,我们在Android平台上使用C++实现算法,通过JNI接口给Java调用。Java层输入Android的Bitmap对象,输出为图片指纹,再通过对比指纹的汉明距离,我们即可判断出来解码是否正常。

Java层接口签名如下:

public native long getHash(Bitmap bitmap, int algorithm);public native long getHammingDistance(long hash1, long hash2);

下面分析一下感知哈希实现的方法和背后的原理,使之知其然,知其所以然。

图片的构成


图一

图二

我们知道图片由RGB三原色构成这称之为加色法,我们可以认为图片有三个维度(暂不考虑Alpha)。分析上面两幅图,图一为原图,可以发现图片里蕴含的大部分信息都是低频的,比如天空,绿叶,树枝等,他们很少变化。高频信息是小鸟的眼睛,嘴巴等细节。图二是把图一经过缩放且只保留亮度信息,可以看到这有效的移除了图片的细节,即高频信息,展示了图片的低频部分。图片的低频部分决定了图片的大体结构,高频部分则完善了图片的细节。我们在对比图片是否相似的时候,其实更关注的是中低频部分的差异度。

在实践中,我们可以把图片从RGB转换为YCbCr格式,只提取Y的部分参与计算,实现降维,以减少运算量。再把图片缩放到32*32大小,丢弃掉大部分高频信息。由于进行了降维和缩放,后续步骤我们的运算量已大大减少。
把图片从空域转换到频域,我们需要使用DCT(二维离散余弦变换)。DCT也是JPEG以及H264压缩算法的核心部分,感兴趣的可以继续深入了解视频压缩算法的相关研究。

感知哈希与DCT(离散余弦变换)

为了让大家深入了解背后的原理,这里打算展开介绍一下DCT,以及它为什么能检测出来图片的相似程度。本文恐怕是网络上能找到讲解DCT最详细的一篇文章了,如果你对背后的原理不感兴趣,也可以直接跳过。


从空域到频域

DCT由如下的公式定义,N和M为矩阵的行数和列数

$$
\\begin{equation}
F(u, v) = \\left (\\frac{2}{N} \\right )^{\\frac{1}{2}} \\left (\\frac{2}{M} \\right )^{\\frac{1}{2}} C(u)C(v) \\sum_{i=0}^{N-1}\\sum_{j=0}^{M-1} f(i,j)cos\\left [\\frac{\\left(2i+1\\right)u\\pi}{2N} \\right ]cos\\left [\\frac{\\left(2j+1\\right)v\\pi}{2N} \\right ]
\\end{equation}
$$

$$
C(\\varepsilon) =
\\begin{cases}
\\frac{1}{\\sqrt{2}}\u0026amp; \\text{for}\\ \\varepsilon = 0\\\\\\
1\u0026amp; \\varepsilon\u0026gt;0
\\end{cases}\\
$$

其中:

  • u,v = 离散频率变量(0,1,2…7)
  • f(i,j) = 图像在i行j列的像素值
  • F(u,v) = DCT结果

我们先研究一个最简单的场景,假设图片像素值如下:

$$
\\begin{bmatrix}
1 \u0026amp;3 \\\\\\
2\u0026amp; 0
\\end{bmatrix}
$$

当N和M都为2时,上述公式可简化为:

$$
\\begin{equation}
F(u,v) = C(u)C(v) \\sum_{i=0}^{1}\\sum_{j=0}^{1} f(i,j)cos\\left [\\frac{\\left(2i+1\\right)u\\pi}{4} \\right] cos\\left [\\frac{\\left(2j+1\\right)v\\pi}{4} \\right]
\\end{equation}
$$

下面我们来计算二维DCT

即,结果是:

$$
\\begin{bmatrix}
3\u0026amp;0\\\\\\
1\u0026amp;-2
\\end{bmatrix}
$$

用Python的相关模块可以交叉验证我们的计算结果:

\u0026gt;\u0026gt;\u0026gt; import numpy as np\u0026gt;\u0026gt;\u0026gt; from scipy.fftpack import dct\u0026gt;\u0026gt;\u0026gt; d=np.matrix([[1,3],[2,0]])\u0026gt;\u0026gt;\u0026gt; dct(dct(d,axis=0,norm=\u0026quot;ortho\u0026quot;),axis=1,norm=\u0026quot;ortho\u0026quot;)array([[ 3.,  0.],       [ 1., -2.]])

在实践上,上述方式的计算效率不高,更加简便的计算方式是使用DCT矩阵:

若N取2,得到DCT矩阵

$$
\\begin{vmatrix}
\\frac{1}{\\sqrt{2}} \u0026amp; \\frac{1}{\\sqrt{2}} \\\\\\
cos(\\frac{\\pi}{4}) \u0026amp; cos(\\frac{3\\pi}{4})
\\end{vmatrix}
$$

若N取8,得到的矩阵是这样的

其中i=0时,即第0行,称为DC分量,i=1-7成为AC分量,用图表形式表示如下


i=1

i=2

i=3

i=4

i=5

i=6

i=7

有这样一个矩阵的话,我们再进行DCT变换就非常简单了:

$$
D=TMT^T
$$

其中:

  • T = DCT矩阵
  • M = 图像数据
  • D = DCT结果

这是对一张8*8图片应用DCT变换得到的矩阵结果:

这个矩阵最左上角是低频信息,右下角是高频信息。有个神奇的东西叫基准样式。

信不信由你,任意一张8*8的图,都可以由标准图中的的小图以一定比例叠加而合成,而每个小图的权重,由DCT变换得到的矩阵决定,是不是很有意思。DCT变换后左上角一般是比较大的数字,而右下角一般是比较小的数字,这暗含了图片中低频信息占的比重较多,因此我们在做图片或者视频编码压缩的时候,正是通过量化舍弃右下角的高频信息,来实现信息的压缩。

图片差异度

我们在对比图片差异的时候,正是通过对比频域信息来实现的。在我们的实现中,首先把软硬件解码后的图片转成YCbCr格式,只提取其中的Y,实现降维,再把图片缩放到32*32大小,进一步减少运算量,同时舍弃了一部分高频信息。再应用32*32的DCT把图片转换到频域,从频域矩阵中提取8*8中低频区域的系数,计算算数平均值。

$$
D = \\frac{\\sum_{i=2}^{9}\\sum_{j=2}^{9}f(i,j)}{64}
$$

矩阵中的每个值再与D比较,大于D计1,小于D计0,按位存储,我们即可得到一个图片指纹。通过计算两个图片指纹的差异,我们就可以得到可以量化图片差异度的数字。
当差异为0时,我们认为两张图片完全一样,差异越大,表明图片越不相似。对于解码出现绿屏,花屏的情况,我们可以有效的检测出来。

绿屏案例,相似度24:

花屏案例,相似度20:

检测Demo截图:

图片相似度计算:深入理解DCT变换以及感知哈希相关推荐

  1. python 图像识别_python图像识别之图片相似度计算

    作者 | a1131825850疯子 来源 | Python爬虫scrapy 原文 | python图像识别---------图片相似度计算 1.背景 要识别两张图片是否相似,首先我们可能会区分这两张 ...

  2. 【python 以图搜图】三种图片相似度计算融合算法

    目标:在一个文件夹找出相似度较高的图片,达到以图搜图的目的. 我找了十组,都是高度相似的图片. 核心算法: 1.分别自定义三种计算图片相似度算法,计算图片相似度算法ORB算法,以及局部敏感哈希phas ...

  3. MATLAB对autumn.tif文件计算二维DCT变换

    %对autumn.tif文件计算二维DCT变换 RGB = imread('autumn.tif'); I = rgb2gray(RGB); %真彩色图像转换成灰度图像 J = dct2(I); %计 ...

  4. Python图像识别,图片相似度计算!

    1.背景 要识别两张图片是否相似,首先我们可能会区分这两张图是人物照,还是风景照等......对应的风景照是蓝天还是大海......做一系列的分类. 从机器学习的的角度来说,首先要提取图片的特征,将这 ...

  5. 连连看不一样的玩法,利用python进行图片相似度计算

    先放制作好的游戏视频链接:(纯粹是兴趣分享) 连连看不一样的玩法-图像相似度识别-python_单机游戏热门视频 https://www.ixigua.com/7076826558106698253? ...

  6. python图像识别之图片相似度计算

    作者 | a1131825850疯子  来源 | Python爬虫scrapy 1.背景 要识别两张图片是否相似,首先我们可能会区分这两张图是人物照,还是风景照等-对应的风景照是蓝天还是大海-做一系列 ...

  7. python图片相似度计算_python Opencv计算图像相似度过程解析

    这篇文章主要介绍了python Opencv计算图像相似度过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 一.相关概念 一般我们人区分谁是谁 ...

  8. python相册图片处理_Python实现图片相似度计算

    图片相似度 _ 概述 今天在用一个软件清理手机时,看到了一个比较好的功能:相似图片删除.软件识别出相册中类似的图片,删除相似图片,进而释放手机存储. 上网查了这个功能的基本实现算法,有挺多算法求图片相 ...

  9. 广告行业中那些趣事系列39:实战广告场景中的图片相似度识别任务

    导读:本文是"数据拾光者"专栏的第三十九篇文章,这个系列将介绍在广告行业中自然语言处理和推荐系统实践.本篇从理论到实践介绍了广告场景中的图片相似度识别任务,对于希望解决图片相似度识 ...

最新文章

  1. 理解Docker——深入引擎室
  2. 大S变汪太!与汪小菲注册结婚
  3. element-- 修改MessageBox 弹框 中确定和取消按钮顺序
  4. 分区表导入导出[未完]
  5. python人工智能——机器学习——转换器与估计器
  6. nowcoder 河 我 车 题 错 天 乐 赛 倍增处理
  7. Unity C# namespace 命名空间的使用
  8. oracle监听启动很慢
  9. (42)Xilinx FIFO IP核配置(三)(第9天)
  10. Unix 电子书大全
  11. 13 -3 jquery选择器和 jquery动画
  12. jekins构建通知邮件配置及邮件附件设置,jenkins构建通知邮件没有RF的log和report文件...
  13. 如何干净完整卸载office2010
  14. 怎么在计算机上设置复印机双面打印,Word如何设置双面打印
  15. 响应式设计中的HTML5
  16. 【Spark】(task5)SparkML基础(分类 | 聚类模型)
  17. 【目标检测论文解读复现NO.20】基于改进Yolov5的地铁隧道附属设施与衬砌表观病害检测方法
  18. PHP文件上传接口(带参数)
  19. Redis数据库的部署及常用命令
  20. 移动端适配多种方案详细分析

热门文章

  1. 中断优先级和中断线程优先级
  2. FFMPEG音频解码浅析
  3. MATLAB——根轨迹原理及其Matlab绘制
  4. 9章 RxJava混合实战
  5. 史上最全Maven教程(一)
  6. 积分和微分电路结构原理带Multisim仿真
  7. 如何利用训练好的神经网络进行预测
  8. 什么模式才是安防渠道商们的未来?
  9. 彻底删除MySQL57服务
  10. php怎么获取html span标签的值_如何获取PHP中所有html元素的列表?