困难都是暂时的 發表於 2020-3-23 22:33:00

二维DCT变换 | Python实现

<h2 id="引言">引言</h2>
<ul>
<li>最近专业课在学信息隐藏与数字水印,上到了变换域隐藏技术,提到了其中的<code>DCT</code>变换,遂布置了一个巨烦人的作业,让手动给两个<span class="math inline">\(8\times8\)</span>的矩阵做二维<code>DCT</code>变换,在苦逼的算了一小时后,我决定放弃,转而决定写脚本来解决,<span class="math inline">\((๑•̀ㅂ•́)و✧\)</span>,正好看网上好像只有<code>matlab</code>的脚本,好像没人用<code>Python</code>来写这个,遂打算搞一个(你就是纯粹为了偷懒不做作业<span class="math inline">\((* ̄rǒ ̄))\)</span></li>
</ul>
<h3 id="二维dct变换原理">二维DCT变换原理</h3>
<ul>
<li>
<p>还是要普及一下的嘛,毕竟让我头疼了一下午的东西,当然也要好好给你们分享一下啦ԅ(¯﹃¯ԅ)</p>
</li>
<li>
<p><code>DCT(Discrete Cosine Transform)</code>,又叫离散余弦变换,它的第二种类型,经常用于信号和图像数据的压缩。经过<code>DCT</code>变换后的数据能量非常集中,一般只有左上角的数值是非零的,也就是能量都集中在离散余弦变换后的直流和低频部分</p>
</li>
<li>
<p>1、一维<code>DCT</code>变换<br>
要弄懂二维离散余弦变换,首先我们需要先了解它在一维下的情况,具体表达式如下:<br>
<span class="math inline">\(F(0)=\dfrac{1}{\sqrt{N}}\sum_{x=0}^{N-1} f(x)\)</span> <span class="math inline">\(...........1\)</span><br>
<span class="math inline">\(F(u)=\sqrt{\dfrac{2}{N}}\sum_{x=0}^{N-1} f(x) \cos{\dfrac{(2x+1)u\pi}{2N}}\)</span> <span class="math inline">\(...........2\)</span><br>
式中<span class="math inline">\(F(u)\)</span>是第<span class="math inline">\(u\)</span>个余弦变换值,<span class="math inline">\(u\)</span>是广义频率变量,<span class="math inline">\(u=1,2,….,N-1;f(x)\)</span>是时域<span class="math inline">\(N\)</span>点序列。<span class="math inline">\(x= 1,2,….,N-1;\)</span></p>
</li>
<li>
<p>2、二维<code>DCT</code>变换<br>
二维离散余弦变换可由下列表达式表示:<br>
<span class="math inline">\(F(0,0)=\dfrac{1}{N}\sum_{x=0}^{N-1}\sum_{y=0}^{N-1} f(x,y)\)</span> <span class="math inline">\(...........3\)</span><br>
<span class="math inline">\(F(0,v)=\dfrac{\sqrt{2}}{N}\sum_{x=0}^{N-1}\sum_{y=0}^{N-1} f(x,y) \cdot \cos{\dfrac{(2y+1)v\pi}{2N}}\)</span> <span class="math inline">\(...........4\)</span><br>
<span class="math inline">\(F(u,0)=\dfrac{\sqrt{2}}{N}\sum_{x=0}^{N-1}\sum_{y=0}^{N-1} f(x,y) \cdot \cos{\dfrac{(2x+1)u\pi}{2N}}\)</span> <span class="math inline">\(...........5\)</span><br>
<span class="math inline">\(F(u,v)=\dfrac{2}{N}\sum_{x=0}^{N-1}\sum_{y=0}^{N-1} f(x,y) \cdot \cos{\dfrac{(2x+1)u\pi}{2N}}\cdot \cos{\dfrac{(2y+1)v\pi}{2N}}\)</span>   <span class="math inline">\(...........6\)</span><br>
<span class="math inline">\(6\)</span>是二维离散余弦变换的正变换公式,其中<span class="math inline">\(f(x,y)\)</span>是空间域一个<span class="math inline">\(N*N\)</span>的二维向量元素,即一个<span class="math inline">\(N*N\)</span>的矩阵,<span class="math inline">\(x,y = 0,1,2,…,N-1;F(U,V)\)</span>是经计算后得到的变换域矩阵,<span class="math inline">\(u,v = 0,1,2,….,N-1\)</span>.求和可分性是二维离散余弦变换的一个重要特征,因此我们可以用下式表示<span class="math inline">\(6\)</span>:<br>
<span class="math inline">\(F(u,v)=\dfrac{2}{N}\sum_{x=0}^{N-1} \cdot \cos{\dfrac{(2x+1)u\pi}{2N}}{\sum_{y=0}^{N-1} f(x,y) }\cdot \cos{\dfrac{(2y+1)v\pi}{2N}} ..........7\)</span><br>
由一维和二维的离散余弦变换公式性质可以推导得到二维离散余弦变换也可以写成矩阵相乘形式:<br>
<span class="math inline">\(F=A..............8\)</span></p>
</li>
<li>
<p><span class="math inline">\(A\)</span>为一维离散余弦变换的变换系数矩阵,<span class="math inline">\(A^{T}\)</span>是<span class="math inline">\(A\)</span>的转置矩阵</p>
</li>
<li>
<p>对图像进行二维离散余弦变换<span class="math inline">\((2D-DCT)\)</span>的步骤<br>
1.获得图像的二维数据矩阵<span class="math inline">\(f(x,y)\)</span>;<br>
2.求离散余弦变换的系数矩阵<span class="math inline">\(A\)</span>;<br>
3.求系数矩阵对应的转置矩阵<span class="math inline">\(A^{T}\)</span>;<br>
4.根据公式<span class="math inline">\(F=A\times\times A^{T}\)</span>计算离散余弦变换;</p>
</li>
<li>
<p>注:公式的大致推导,由于<span class="math inline">\(A\)</span>都是正交阵,所以<span class="math inline">\(A^{-1}=A^{T}\)</span>,故<span class="math inline">\(Y=A\times\times A^{T} ,f(x,y)=A^{T}\times Y \times A=A^{T}\times A\times\times A^{T}\times A\)</span></p>
</li>
</ul>
<h4 id="参考链接httpswwwcnblogscomlatencytimep10228938html">参考链接:<code>https://www.cnblogs.com/latencytime/p/10228938.html</code></h4>
<h4 id="参考链接httpsblogcsdnnetallen_sdzarticledetails83279210">参考链接:<code>https://blog.csdn.net/allen_sdz/article/details/83279210</code></h4>
<h3 id="python编程实现">Python编程实现</h3>
<ul>
<li>大家注意上述的第<span class="math inline">\(8\)</span>个式子,将变换的两个<span class="math inline">\(\sum_{i=0}^n\)</span>转变成了变换矩阵和转置矩阵以及代转换矩阵之间乘积的问题(注意这里的乘是指的叉乘)</li>
<li>遂可以发现<span class="math inline">\(DCT\)</span>后的矩阵应等于<span class="math inline">\(A\times X \times A^{T}\)</span></li>
<li>此外,对于<span class="math inline">\(x,y\)</span>同时为0的情况,其参数要单独考虑</li>
<li>大致的思路就是,由于直接计算变换比较繁琐,所以我们就先对于一个单位阵进行操作运算,将其变成一个<code>DCT</code>的变换矩阵,而后在与代算矩阵和转置矩阵叉乘即可。</li>
<li>至此我们就可以着手写脚本了,这里主要是用了两个库<code>numpy</code>和<code>math</code></li>
</ul>
<pre><code># -*- coding:utf-8 -*-
# Author:Konmu
# DCT二维变换

from numpy import array as matrix, arange,zeros,transpose,matmul,ones
from math import sqrt,cos,pi

'''
作业代转化矩阵1
a=matrix([,
          ,
          ,
          ,
          ,
          ,
          ,
          ])
'''
a=ones((8,8))#生成单位阵
for i in range(8):
    a=matrix(*8)
# 生成全是128的矩阵(作业代转化矩阵2)
'''
测试数据
a=matrix([,
          ,
          ,
          ])
'''
A=zeros((8,8))#生成0矩阵
shape=a.shape#获取维数
for i in range(8):
    for j in range(8):
      if(i == 0):
            x=sqrt(1/shape)
      else:
            x=sqrt(2/shape)
      A=x*cos(pi*(j+0.5)*i/shape)#与维数相关

A_T=A.transpose()#矩阵转置
Y1=matmul(A,a)#矩阵叉乘
Y=matmul(Y1,A_T)
print(Y)
'''
想要近似值可以尝试这样输出
for i in range(shape):
    for j in range(shape):
      print('{:^8.4f}'.format(Y),end='\n')
print()
'''
</code></pre>
<ul>
<li>结果:<br>
0和255的对称矩阵<br>
<img src="https://img2020.cnblogs.com/blog/1973814/202003/1973814-20200330143208604-1656343398.png" alt="DCT" loading="lazy"><br>
128的单元素矩阵<br>
<img src="https://img2020.cnblogs.com/blog/1973814/202003/1973814-20200330143100028-1957247799.png" alt="DCT" loading="lazy"><br>
测试矩阵<br>
<img src="https://images.cnblogs.com/cnblogs_com/Konmu/1674439/t_2003231400199.png" alt="DCT" loading="lazy"></li>
</ul>
<h2 id="结语">结语</h2>
<ul>
<li>ok,完美撒花,结束,交作业喽ヾ(≧O≦)〃嗷~C</li>
</ul><br><br>
来源:https://www.cnblogs.com/Konmu/p/12555802.html
頁: [1]
查看完整版本: 二维DCT变换 | Python实现