12.4.3 利用Arnold变换置乱图像(1)
Arnold变换是Arnold在遍历理论研究中提出的一种变换。由于Arnold本人最初对一张猫的图片进行了此种变换,因此它又被称为猫脸变换。Cat映射可以把图像中各像素点的位置进行置换,使其达到加密的目的,因而在数字图像置乱中的应用是非常广泛的。Cat映射的表达式如下:

特别地,当a=b=1,N=1时,Cat映射的方程可写为:

为了方便,通常写成矩阵形式:

其中,mod1表示只取小数部分,即xmod1=x [x],因此(xn, yn)的相空间被限制在单位正方形内。如图12-11所示是Cat映射的变换示意图,从中很容易发现其产生密图的两个因素:拉伸和折叠。Cat映射通过与矩阵C相乘使x、y都变大,相当于拉伸;而取模运算使x、y又折回单位矩形内,相当于折叠。同时Arnold映射是一一映射,单位矩阵内的每一点唯一地变换到单位矩阵内的另一点。Cat映射可以用于图像置乱加密,而且基于Arnold的Cat图像置乱也是目前研究最为广泛的一种置乱方案。

对于数字图像来说,可以将其看成是一个函数在离散网格点处的采样值,这样就得到了一个表示图像的二维像素矩阵。矩阵中元素的值是对应点处的灰度值或RGB颜色分量值。对于数字化图像而言,这里所说的位置移动实际上是对应点的灰度值或者RGB颜色值的移动,即将原来点(x, y)处像素对应的灰度值或RGB颜色分量值移动至变换后的点(x′, y′)处。如果对一个数字图像迭代地使用离散化的Arnold变换,即将左端输出的(x′, y′)作为下一次Arnold变换的输入,则可以重复这个过程一直做下去。当迭代到某一步时,如果出现的图像呈现出杂乱无章、无法辨识的情况,那么就得到了一幅置乱图。
下面我们就来编程实现图像的标准Arnold置乱加密。为了简化程序设计,这里仅考虑最基本的情况,即默认待处理的图像的宽和高相等。对于那些宽和高不等的情况,程序将截取其中的一个正方形部分进行处理。这里仍然以MagicHouse为基础进行开发。打开MagicHouse项目,并在其中添加一个对话框,如图12-12所示,该对话框将集猫脸变换/逆变换功能于一体。主程序菜单栏中的不同菜单项在调用该对话框时,通过传递一个布尔值来判断此时应选择启动正变换过程还是逆变换过程。

为上述对话框创建一个类CDlgCat,下面列出DlgCat.cpp文件的核心代码清单,请读者注意这里略去了部分系统自动生成的代码。该文件的完整源代码及项目中其他文件的代码清单请读者参看随书光盘。
- #include "stdafx.h"
- #include "MagicHouse.h"
- #include "DlgCat.h"
-
- //CDlgCat 对话框
-
- IMPLEMENT_DYNAMIC(CDlgCat, CDialog)
-
- CDlgCat::CDlgCat(CWnd* pParent /*=NULL*/, BYTE *our_image_Buffer,
- BYTE* temp_imageBuffer, unsigned int X_image,
- unsigned int Y_image, bool signal)
- : CDialog(CDlgCat::IDD, pParent)
- , m_key2(0)
- , m_key1(0)
- , m_times(0)
- {
- xImage=X_image;
- yImage=Y_image;
- image_origin = our_image_Buffer;
- image_temp = temp_imageBuffer;
- sign = signal;
- }
-
- //此处省略了部分系统自动生成的代码
-
- //CDlgCat 消息处理程序
- BOOL CDlgCat::OnInitDialog()
- {
- CDialog::OnInitDialog();
-
- m_key1 = 30;
- m_key2 = 6;
- m_times = 1;
- UpdateData(false);
- return TRUE;
- }
-
- void CDlgCat::OnBnClickedOk()
- {
- UpdateData(true);
-
- int a = 1;
- int d = m_key1 * m_key2 + 1;
- int X_location;
- int Y_location;
-
- int length = (xImage>yImage) yImage:xImage;
- int sum = xImage * yImage * 4;
- BYTE *arnoldImageBuffer = new BYTE[sum];
- memcpy(arnoldImageBuffer,image_origin,sum);
-
- if(sign)
- {
- for(int i =0; i<m_times; i++)
- {
- for(int j=0; j < yImage;j++)
- {
- for(int k=0; k< xImage; k++)
- {
- if(k>=length||j>=length)
- break;
- X_location = (a*k + m_key1*j)%length;
- Y_location = (m_key2*k + d*j)%length;
-
- image_temp[(X_location + xImage*Y_location)*4]
- = arnoldImageBuffer[(k + j*xImage)*4];
- image_temp[(X_location + xImage*Y_location)*4 + 1]
- = arnoldImageBuffer[(k + j*xImage)*4 +1];
- image_temp[(X_location + xImage*Y_location)*4 + 2]
- = arnoldImageBuffer[(k + j*xImage)*4 +2];
- }
- }
- memcpy(arnoldImageBuffer,image_temp,sum);
- }
- }
- else if (!sign)
- {
- for(int i=0; i< m_times; i++)
- {
- for(int j=0; j < yImage;j++)
- {
- for(int k=0; k< xImage; k++)
- {
- if(k>=length||j>=length)
- break;
-
- X_location = (d*k - m_key1*j)%length;
- Y_location = (a*j - m_key2*k)%length;
- if(X_location<0)
- X_location += length;
- if(Y_location<0)
- Y_location += length;
- image_temp[(X_location + xImage*Y_location)*4]
- = arnoldImageBuffer[(k + j*xImage)*4];
- image_temp[(X_location + xImage*Y_location)*4 + 1]
- = arnoldImageBuffer[(k + j*xImage)*4 +1];
- image_temp[(X_location + xImage*Y_location)*4 + 2]
- = arnoldImageBuffer[(k + j*xImage)*4 +2];
- }
- }
- memcpy(arnoldImageBuffer, image_temp, sum);
- }
- }
-
- delete[] arnoldImageBuffer;
- OnOK();
- }