一、简介
1 数字图像置乱的目的
到目前为止,比较成熟的信息隐藏算法基本上都是以图像作为载体的。图像置乱,顾名思义,就是把图像打乱,隐藏原始图像的真实内容。数字图像置乱和信息文件加密思想类似,它主要是通过对数字图像的像素位置做变换来“扰乱”图像,使其变得面目全非、杂乱无章,从而隐藏图像所要表达的真实信息。图像置乱可以达到两个目的:
1.1 加密处理
图像置乱变换是一种基于内容的图像加密方法,与不知道密钥对已加密信息进行解密一样,倘若不知道图像置乱所采用的算法,同样难以恢复原始图像的信息。
1.2 增强图像伪装的鲁棒性(鲁棒性:是指在经历多种无意或有意的信号处理过程后,数字水印仍能保持部分完整性并能被准确鉴别。可能的信号处理过程包括信道噪声、滤波、数/模与模/数转换、重采样、剪切、位移、尺度变化以及有损压缩编码等。主要用于版权保护的数字水印易损水印(Fragile Watermarking),主要用于完整性保护,这种水印同样是在内容数据中嵌入不可见的信息。当内容发生改变时,这些水印信息会发生相应的改变,从而可以鉴定原始数据是否被篡改。)
置乱技术作为信息隐藏的预处理手段,可以大大增强图像信息伪装的鲁棒性。主要体现在3个方面:
①图像置乱以后,将得到一幅杂乱无序的图像,没有内容,没有纹理,也没有形状,从中无法读取出有意义的信息。
我们将这样一幅“三无”图像嵌入到另一幅普通图像里时就不易引起这幅图像在内容、纹理、形状上的太大改变,甚至觉察不出发生了改变,这样人眼就不易识别,从而逃出了第三方的视线,可以更好地保证水印信息的隐蔽性
②由于秘密图像是置乱以后的图像,第三方难以对它的内容、纹理、形状等进行统计分析,这样即便他们截获到了秘密图像,也对此无能为力。如果第三方企图对秘密图像进行反置乱运算,这也是非常困难的,因为图像置乱的方法很多,每种方法又可以使用不同的置乱算法,设置不同的参数,加密方可以根据自己的想法得到很多不同的结果,这给企图进行反置乱的第三方带来了很大的困难,需要耗费巨大的计算量来穷举测试各种可能性。
③如果第三方进行反置乱运算不成,也可能会在隐蔽的载体上进行恶意修改,用置乱的方法也可以达到抵抗这些攻击的目的。因为合法接收者对秘密图像进行反置乱的时候,会使第三方在图像上所涂画的信息分散到画面的各个位置,形成点状的随机噪声,对视觉影响的程度不是很大。
图1是在置乱图像上进行涂改和剪裁两种恶意修改以后,恢复出的秘密图像。可以看到,秘密图像的内容依然可见。为了使提取的图像信息更为清晰,还可以对破坏严重的图像进行中值滤波等方面的处理,以去除随机噪声。
当然,不应该忽视的是图像置乱在一定程度上增加了加密计算的复杂度和计算量,但是与非法攻击者可能花费的更大的计算量相比,图像置乱仍是一种值得付出代价的、相对安全的手段。正是因为如此,图像置乱技术在数字水印技术中具有非常重要的作用和意义。
2 数字图像置乱的方法
数字图像的置乱可以在位置空间、色彩空间、频率空间上进行。随着计算机技术和数字图像处理技术的发展,很多文献对图像置乱提出了不同的置乱算法,大体上可以分为线性变换、几何变换和仿射变换。目前研究较多的置乱技术包括Fibonacci变换、Arnold变换、Hilbert曲线变换、E-曲线变换、Gray变换、仿射变换、幻方、正交拉丁方变换等方法。无论哪一种置乱技术都是可逆的,或者是具有周期性的,即多次迭代或者做反变换均能恢复原图像。
下面仅Arnold变换为例讨论数字图像置乱。
2.1 Arnold变换
Arnold变换是V.J.Arnold在遍历理论的研究中提出的一种变换,原意为catmapping,俗称猫脸变换。Arnold变换直观、简单、具有周期性,使用非常方便。Arnold变换的原理是先作x轴方向的错切变换,再作y轴方向的错切变换,最后的模运算相当于切割回填操作,其变换示意图如图4所示。
Arnold变换的置乱效果图如图5所示。
3 图像置乱效果的评定
通常,图像置乱度的评定应该主要考虑以下几个方面:①像素移动的距离;②像素分散的均匀度;③相对于原始图像差别;④图像视觉感知效果。
一般来说,置乱后的秘密图像越“乱”,它的隐蔽性越好,安全性也越高。从置乱变换的概念可以看出,位置空间置乱的实质就是将原始图像各个像素的位置进行了移动,从直观上来看,像素移动的距离越大,其置乱程度也就越大。另一方面,像素位置发生移动以后,像素分散的均匀程度也是要考虑的一个问题。如果图像的局部像素都向同一个方向平行移动的话,那么即使平移的距离很大,它置乱效果也是不理想的。
一般说来,原来集中在一起的像素,置乱以后分散得越均匀,图像的置乱效果越好。再者,置乱变换的目的就是最太限度地隐蔽原始图像的信息,因此,置乱图像相对于原始图像的差别越大,其置乱效果越好,因为置乱变换虽然不改变原始图像像素的灰度值,但是它会改变像素点邻域的灰度值分布,所以置乱图像相对于原始图像越“乱”,表明该置乱算法越有效。
二、源代码
function varargout = ladingfang(varargin)
% LADINGFANG M-file for ladingfang.fig
% LADINGFANG, by itself, creates a new LADINGFANG or raises the existing
% singleton*.
%
% H = LADINGFANG returns the handle to a new LADINGFANG or the handle to
% the existing singleton*.
%
% LADINGFANG('CALLBACK',hObject,eventData,handles,...) calls the local
% function named CALLBACK in LADINGFANG.M with the given input arguments.
%
% LADINGFANG('Property','Value',...) creates a new LADINGFANG or raises the
% existing singleton*. Starting from the left, property value pairs are
% applied to the GUI before ladingfang_OpeningFunction gets called. An
% unrecognized property name or invalid value makes property application
% stop. All inputs are passed to ladingfang_OpeningFcn via varargin.
%
% *See GUI Options on GUIDE's Tools menu. Choose "GUI allows only one
% instance to run (singleton)".
%
% See also: GUIDE, GUIDATA, GUIHANDLES
% Edit the above text to modify the response to help ladingfang
% Last Modified by GUIDE v2.5 05-Jan-2005 22:18:40
% Begin initialization code - DO NOT EDIT
gui_Singleton = 1;
gui_State = struct('gui_Name', mfilename, ...
'gui_Singleton', gui_Singleton, ...
'gui_OpeningFcn', @ladingfang_OpeningFcn, ...
'gui_OutputFcn', @ladingfang_OutputFcn, ...
'gui_LayoutFcn', [] , ...
'gui_Callback', []);
if nargin & isstr(varargin{1})
gui_State.gui_Callback = str2func(varargin{1});
end
if nargout
[varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
else
gui_mainfcn(gui_State, varargin{:});
end
% End initialization code - DO NOT EDIT
% --- Executes just before ladingfang is made visible.
function ladingfang_OpeningFcn(hObject, eventdata, handles, varargin)
% This function has no output args, see OutputFcn.
% hObject handle to figure
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
% varargin command line arguments to ladingfang (see VARARGIN)
% Choose default command line output for ladingfang
handles.output = hObject;
% Update handles structure
guidata(hObject, handles);
% This sets up the initial plot - only do when we are invisible
% so window can get raised using ladingfang.
if strcmp(get(hObject,'Visible'),'off')
% plot(rand(5));
end
global h1 h2
h1=handles.axes1;
h2=handles.axes2;
%-----------------初始化界面属性
set(handles.edit1,'string','1');
set(handles.edit2,'string','2');
set(handles.edit3,'string','125');
set(handles.pushbutton2,'Visible','off');
G=imread('LENA256.BMP');
set(gcf,'CurrentAxes',h1);
imshow(G);
title('原图像');
set(h2,'Visible','off');
% UIWAIT makes ladingfang wait for user response (see UIRESUME)
% uiwait(handles.figure1);
% --- Outputs from this function are returned to the command line.
function varargout = ladingfang_OutputFcn(hObject, eventdata, handles)
% varargout cell array for returning output args (see VARARGOUT);
% hObject handle to figure
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
% Get default command line output from handles structure
varargout{1} = handles.output;
%%%%%%%%%%%%%%%%%%%%%%%%%%%% 加密函数 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function pushbutton1_Callback(hObject, eventdata, handles)
% hObject handle to pushbutton1 (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
axes(handles.axes1);
cla;
global h1 h2
%------------更新并获取各对象属性
Times = str2num(get(handles.edit1, 'string'));
X= str2num(get(handles.edit2, 'string'));
Y= str2num(get(handles.edit3, 'string'));
popup_sel_index = get(handles.popupmenu1, 'Value');
switch popup_sel_index
case 1
G=imread('lena256.bmp');
set(gcf,'CurrentAxes',h1);
imshow(G);
title('原图像');
%-----验证输入数据的有效性
N = str2double(get(handles.edit1,'String'));
Errstr = '';
Errstr = '变换次数必须为正整数!';
end
if ~isempty(Errstr)
errordlg(Errstr);
return
end
D(1) =str2double(get(handles.edit2,'String'));
D(2) =str2double(get(handles.edit3,'String'));
Errstr = '';
if isnan(D(1)) | ~(floor(D(1)) == D(1)) | (D(1) < 1)| (D(1)>255)
Errstr = '参数1必须为1至255正整数!';
end
if ~isempty(Errstr)
errordlg(Errstr);
return
end
Errstr = '';
if isnan(D(2)) | ~(floor(D(2)) == D(2)) | (D(2) < 1)| (D(1)>255)
Errstr = '参数2必须为1至255正整数!';
end
if ~isempty(Errstr)
errordlg(Errstr);
return
end
if D(1) == D(2)
Errstr = '参数1与参数2必须不同!';
end
if ~isempty(Errstr)
errordlg(Errstr);
return
end
%-----------验证结束
%-----------计算期间,禁用部分控件
mousefrm(0,'watch');
set(handles.popupmenu1,'enable','off');
set(handles.popupmenu2,'enable','off');
set(handles.edit1,'enable','off');
set(handles.edit2,'enable','off');
set(handles.edit3,'enable','off');
set(handles.pushbutton1,'enable','off');
set(handles.pushbutton2,'enable','off');
%----------------------------------------
set(gcf,'CurrentAxes',h2);
I=G;
[u,v]=zhengjiaodui(X,Y);
%----------恢复控件的可用性
set(handles.popupmenu1,'enable','on');
set(handles.popupmenu2,'enable','on');
set(handles.edit1,'enable','on');
set(handles.edit2,'enable','on');
set(handles.edit3,'enable','on');
set(handles.pushbutton1,'enable','on');
set(handles.pushbutton2,'enable','on');
mousefrm(0,'arrow');
%--------------------------------------
case 2
G=imread('LENA256.BMP');
set(gcf,'CurrentAxes',h1);
imshow(G);
title('原图像');
%-----验证输入数据的有效性
N = str2double(get(handles.edit1,'String'));
Errstr = '';
if isnan(N) | ~(floor(N) == N) | (N <= 0)
Errstr = '变换次数必须为正整数!';
end
if ~isempty(Errstr)
errordlg(Errstr);
return
end
D(1) =str2double(get(handles.edit2,'String'));
D(2) =str2double(get(handles.edit3,'String'));
Errstr = '';
if isnan(D(1)) | ~(floor(D(1)) == D(1))
Errstr = '参数1必须为整数!';
end
if ~isempty(Errstr)
errordlg(Errstr);
return
end
Errstr = '';
if isnan(D(2)) | ~(floor(D(2)) == D(2))
Errstr = '参数2必须为整数!';
end
if ~isempty(Errstr)
errordlg(Errstr);
return
end
%-----------验证结束
mousefrm(0,'watch');
set(gcf,'CurrentAxes',h2);
positiontrans(G,Times,X,Y);
title('加密后');
mousefrm(0,'arrow');
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%% 解密函数 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function pushbutton2_Callback(hObject, eventdata, handles)
% hObject handle to pushbutton2 (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
axes(handles.axes1);
cla;
global h1 h2
Times = str2num(get(handles.edit1, 'string'));
X= str2num(get(handles.edit2, 'string'));
Y= str2num(get(handles.edit3, 'string'));
Times = str2num(get(handles.edit1, 'string'));
UNCODE=imread('code.bmp');
set(gcf,'CurrentAxes',h1);
imshow(UNCODE);
title('解密前');
%-----验证输入数据的有效性
N = str2double(get(handles.edit1,'String'));
Errstr = '';
if isnan(N) | ~(floor(N) == N) | (N <= 0)
Errstr = '变换次数必须为正整数!';
end
if ~isempty(Errstr)
errordlg(Errstr);
return
end
D(1) =str2double(get(handles.edit2,'String'));
D(2) =str2double(get(handles.edit3,'String'));
Errstr = '';
if isnan(D(1)) | ~(floor(D(1)) == D(1)) | (D(1) < 1)| (D(1)>255)
Errstr = '参数1必须为1至255正整数!';
end
if ~isempty(Errstr)
errordlg(Errstr);
return
end
Errstr = '';
if isnan(D(2)) | ~(floor(D(2)) == D(2)) | (D(2) < 1)| (D(1)>255)
Errstr = '参数2必须为1至255正整数!';
end
if ~isempty(Errstr)
errordlg(Errstr);
return
end
if D(1) == D(2)
Errstr = '参数1与参数2必须不同!';
end
if ~isempty(Errstr)
errordlg(Errstr);
return
end
三、运行结果
四、备注
版本:2014a