信息隐藏——第四章 图像信息隐藏数

时间:2024-03-20 07:27:48

从本章开始, 我们将具体接触到许多数字信息的隐写术。为了与后面数字水印技术相区别, 我们也将隐写术称为信息隐秘技术。本章主要阐述图像信息作为秘密信息的隐藏, 即图像降级隐写。
在整个介绍信息隐秘技术部分, 为了统一起见, 我们约定以下名词: 称需要隐秘的信息为秘密信息( secret) , 秘密信息隐藏的媒介叫做载体( cover) , 隐藏后的结果叫做隐蔽载体( stego-cover)
一、图像降级
主体对客体的读写一般应满足以下两个规则:
规则 1: 主体只能向下读, 不能向上读。
规则 2: 主体只能向上写, 不能向下写。
我们通常所说的信息降级, 就是通过将秘密信息嵌入较低安全级别的客体中, 破坏了第二个规则, 从而使机密的信息看上去不再机密。在伪装技术中我们经常要这样做, 以使秘密信息被伪装成为低级别的信息, 不易被发现。图像降级就是伪装技术的一个应用。
二、简单的图像信息伪装技术
1.直接 4bit 替换法
这是将秘密图像信息嵌入载体图像的一种最简单的方法,指直接用秘密图像像素值的高 4bit 去替换载体图像像素值的低 4bit。

% 文件名: imagehide. m
% 函数功能: 直接将秘密图像的高 4bit 隐藏在 RGB 载体图像的 R, G, B 层中所
选的那一层的低 4bit, 并将秘密图像提取出来, 最后显示。要求载体图像的大小大于
等于秘密图像的大小, 且秘密图像是二值或灰度图像
% 输入格式:
% data = imagehide( ′c: \ lenna. bmp′, ′c: \ woman. bmp′, ′c: \mix. bmp′, ′bmp′, 3 )
% 参数说明
% cover 是载体图像的地址
% message 是秘密图像的地址
% goleimage 是隐藏后图像的地址
% permission 是图像的类型
% level 是作为载体的具体层, R 为 1 , G 为 2, B 为 3
% data 是隐藏后图像的矩阵

function data = imagehide( cover, message, goleimage, permission, level)
% 提取图像信息并分层
cover = imread( cover, permission) ;
data = cover;
msg = imread( message, permission) ;
[ row, col] = size( cover) ;
cover1 = cover(∶,∶, level) ;
% 置载体图像 R 层的低 4bit 为 0
for i = 1∶row
		for j = 1∶col /3
				cover1( i, j) = bitand( cover1( i, j) , 240) ;
		end
end
% 置秘密图像的低 4bit 为 0
takemsg4 = bitand( msg, 240) ;
% 将秘密图像的高 4bit 右移 4 位
shiftmsg4 = bitshift( takemsg4, - 4) ;
% 图像隐藏
for i = 1∶row
		for j = 1∶col /3
				cover1( i, j) = bitor( cover1( i, j) , shiftmsg4( i, j) ) ;
		end
end
% 写回并保存
data(∶,∶, level) = cover1;
imwrite( data, goleimage, permission) ;
% 提取秘密图像信息, 检测隐藏效果
data = imread( goleimage, permission) ;
[ row, col] = size( data) ;
A = data(∶,∶, level) ;
for i = 1∶row
       for j = 1∶col /3
				A( i, j) = bitand( A( i, j) , 15) ;
       end
end
A = bitshift( A, 4) ;
% 显示结果
subplot( 221) , imshow( cover) ; title( ′载体图像′) ;
subplot( 222) , imshow( message) ; title( ′秘密图像′) ;
subplot( 223) , imshow( data) ; title( ′隐藏后的图像′) ;
subplot( 224) , imshow( A) ; title( ′提取的秘密图像′) ;

但无论选择R G B三层中的哪层嵌入,都会在不同程度上对原始图像造成破坏
考虑到第一章中我们阐述的 RGB 颜色模型, 将秘密图像隐藏在一层中, 容易导致该点的色彩向相应的坐标上发生绝对偏移, 从而使得该像素点的色彩的相应分量突出。所以, 我们不能笼统地认为图像隐藏在某层比较好而隐藏在某层不好, 这是因为对于具体的某个像素点其哪个颜色分量突出是不确定的。但是, 我们可以通过改进算法来限制这种颜色沿相应坐标的绝对偏移。

例如, 可将秘密图像像素值的高 4bit 分别藏于载体图像 R, G, B 层像素值的最低位或次低位, 即将秘密图像的高 2bit 藏于 R 层, 另外 2bit 分别藏于 G 层和 B 层, 此时像素色彩的改变就不是沿一个坐标方向而改变, 而是在整个 RGB 空间中发生偏移, 改变后的颜色坐标点与改变前的颜色坐标点的距离( 数学上的范数) 比单纯在一个分量上改变的两点距离要小, 这样对载体图像的影响会更小。在实际应用中, 还应该考虑隐藏的鲁棒性等问题。

2.对第 4bit 的考察
可以发现,直接替换 4 bit 后, 图像还是有一些变化的, 也就是说, 替换容量大使图像的保真度降低( 可通过实验看到替换 3bit 的效果比替换 4bit 的效果要好)
在这种情况下,我们可以用秘密信息图像像素值的高3bit去替换载体图像像素值的低3bit,至于第 4bit 则要具体分析
其假设前提是: 如果只对图像进行 3bit 替换, 是不会对图像的视觉效果造成影响的。事实上, 这种假设是可以成立的

首先, 我们引入一个相似度的概念, 所谓相似度, 是指两图像块中同一坐标下的像素中第 4bit 相同的像素数量占一块图像全部像素的比例, 表示为:μ=s/64
其中 s 为第 4bit 相同的像素数量 64 为 8× 8 块中的总像素数
根据 μ的取值我们来确定该块各像素第 4bit 的隐藏策略。
我们先计算相应块的载体图像与秘密图像在第 4bit 的相似度 μ, 如果 μ大于某一阈值 T, 则可直接用秘密图像的第 4 bit 替换载体图像的第 4bit, 如果 μ小于阈值1 - T, 则先将秘密图像的第 4bit 取反后再替换, 若 μ介于 1 - T 和 T 之间, 则不进行替换。当然, 要用一个替换表对第 4bit 进行替换或取反替换了的块进行记录, 并且将此表也嵌入到载体图像中。编写函数 fourthbitcmp. m 完成记录替换表的实验, 函数代码如下:

% 文件名: fourthbitcmp. m
% 函数功能: 计算秘密图像和选择的载体图像层, 对于第 4bit 的每一个 8× 8 块,哪些可以用秘密图像去替换载体图像, 并返回一个替换表 count, 要求两个图像都可以整数 8× 8 分块
% 输入格式: count = fourthbitcmp( ′c: \lenna. bmp′, ′c: \woman. bmp′, ′bmp′, 3, 0. 7)
% 参数说明:
% cover 是载体图像的地址
% message 是秘密图像的地址
% permission 是图像的类型
% level 是作为载体的具体层。R 为 1, G 为 2 , B 为 3
% count 是替换表
% threshold 是阈值
function count = fourthbitcmp( cover, message, permission, level, threshold)
% 提取图像信息并分层
cover = imread( cover, permission) ;
data = cover;
msg = imread( message, permission) ;
cover1 = cover(∶,∶, level) ;
% 对 cover 和 msg 的第 4bit 进行处理
tempc = cover1;
tempm = msg;
tempc = bitand( tempc, 8) ;
tempm = bitand( tempm, 8) ;
temp = bitxor( tempm, tempc) ;
[ row, col] = size( temp) ;
% 记录图像每个分块的 n 值
k1 = 0;
k2 = 0;
a = row* col /64;
count = zeros( [ 1 a] ) ;
for i = 1∶a
	for m = 1∶8
		for n = 1∶8
				if temp( 8* k1 + m, 8* k2 + n) == 0
					count( 1, i) = count( 1, i) + 1;
				end
		end
	end
	k2 = k2 + 1;
	if k2* 8 == col
			k2 = 0;
					k1 = k1 + 1;
			end
	end
% 计算每块的 μ值并与阈值进行比较
count = count /64;
for i = 1∶a
	if count( i) >= threshold
		count( i) = 1; % 可以替换
			elseif count( i) < 1 - threshold
				count( i) = - 1; % 取反
			else
		        count( i) = 0; % 不能处理
	end
end

依据本算法, 在同一阈值下经不同层计算出的替换表中 0 的个数, 个数越少的层越适宜当做载体。当然, 为了简单起见, 也可以不加分块直接计算秘密图像与载体图像 R、G、B 层中哪一层的相似度高, 就选择哪一层为载体。
三、图像置乱
置乱实际上就是图像的加密, 与加密保证安全性不同的是, 将置乱的图像作为秘密信息再进行隐藏, 可以很大限度地提高隐蔽载体的鲁棒性, 所以图像置乱是信息隐藏中常用的一项技术。
1、变化模板形状的图像置乱算法
变化模板形状的图像置乱算法的思想如下:
① 对原图像取一个固定模板, 模板中像素位置排列如图 4. 10 所示。
② 做一个与原图像模板不同的置乱模板, 如图 4. 11 所示, 在置乱模板中把图像模板中的像素位置按一定次序填入
③ 将置乱模板中的像素位置再按一定的次序填回到原图像模板中就得到了置乱后的图像模板( 图 4. 12 的模板是按从左到右、从上到下的次序依次读取置乱模板中像素位置) 。
信息隐藏——第四章 图像信息隐藏数
可以发现, 这种置乱算法是对合的
与前面 Zigzag 变换一样, 我们也采取查表的方法编写程序。由于我们固定了置乱模板的大小, 所以在对图像置乱前我们要对其进行边界修补。如取置乱模板为 32× 32, 则要求秘密图像的尺寸为 32× 32,64× 64 , 128× 128, …。假设一幅图像的尺寸为 32× 31 , 则应该对其增加 1 列数据。
变换表分为行表和列表, 同一坐标下的行列表中的数据结合起来所指示的像素将被置乱到这一坐标下。
此外, 在图像置乱机制中引入一个简单的**控制。将由**生成的第一个[ 128, 255] 的随机整数与置乱的结果进行模 2 加。编写程序 diamondreplace. m 完成置乱实验。其中需要调用查表程序 replace32 fun. m, 函数代码如下:
( 1 ) 主函数: diamondreplace. m

% 文件名: diamondreplace. m
% 函数功能: 本函数将完成对输入的图像信号按菱形置换策略进行置乱
% 输入格式举例: result = diamondreplace( secretimage, 1983 )
% 参数说明:
% matrix 为输入图像矩阵
% key 为控制**
% result 为置乱后的结果
function result = diamondreplace( matrix, key)
% 分析原图像尺寸并补遗
[ m, n] = size( matrix) ;
rowadd = 32-mod( m, 32) ;
coladd = 32-mod( n, 32 ) ;
if rowadd== 32
rowadd = 0;
end
if coladd== 32
coladd = 0;
end
input = uint8( zeros( [ m + rowadd n + coladd] ) ) ;
input( 1∶m, 1∶n) = matrix;
% **生成随机数
rand( ′seed′, key) ;
control = randint( 1, 1 , [ 128 255] ) ;
% 查表置乱
fun = @replace32fun; % 调用子函数
result = blkproc( input, [ 32 32] , fun) ;
result = bitxor( result, control( 1 , 1) ) ;

( 2 ) 查表函数: replace32fun. m

function result = replace32fun( matrix)
% 行转换表
row = [ 16 15 17 14 16 18 …] % 此处略去, 具体内容请见表 4. 3
col = [ 17 18 17 20 18 16 …] % 此处略去, 具体内容请见表 4 . 4
for i = 1∶32
for j = 1∶32
result( i, j) = matrix( row( i, j) , col( i, j) ) ;
end
end

信息隐藏——第四章 图像信息隐藏数
将图像的原始信息破坏得越大越好, 不过, 这种破坏一定要是可以复原的

2.图像的幻方变换

% 文件名: magicsquares. m
% 函数功能: 本函数将完成 n 阶二维幻方的求取 . 要求 n 为奇数
% 输入格式举例: result = magicsquares( 5)
% 参数说明:
% n 为阶数
% result 为求得的二维幻方
function result = magicsquares( n)
if mod( n, 2) == 0
error( ′n 要求为奇数′) ;
end
result = zeros( n) ;
j = floor( n /2 ) + 1; % 中间 1 列
i = n + 1; % 便于以后从第 n 行开始考虑起
result( 1, j) = 1 ;
for k = 2∶n* n % 依次考虑后 n^2 - 1 个数
i = i - 1 ;
j = j + 1 ; % 行数减 1, 列数加 1
if i < 1 && j > n % 特殊情况 4
i = i + 2 ;
j = j - 1 ;
else
if i < 1 % 特殊情况 1
i = n;
end
if j > n % 特殊情况 2
j = 1;
end;
end;
if result( i, j) == 0
result( i, j) = k;
else % 特殊情况 3
i = i + 2 ;
j = j - 1 ;
result( i, j) = k;
end
end

我们知道, 要图像置乱是为了增加隐藏的鲁棒性。一个置乱的图像无论是合法用户还是非法用户都看不懂, 要使合法用户能完整地读取秘密信息, 就要满足两个条件:
①仅有合法用户知道的**参与运算。
②置乱算法本身可以保证图像复原, 即算法是可逆的。
幻方置乱的思想其实也是查表思想,其运算具有准对合性,具体算法实现后面再阐述
编 写 函 数 magicreplace. m 完 成 置 乱 实 验, 其 中 需 要 调 用 查 表 函 数replacemagicfun. m。前主函数存放 11 阶标准幻方, 子函数存放表 4. 6 , 函数代码如下:
( 1 ) 幻方置乱主函数: magicreplace.m

% 文件名: magicreplace. m
% 函数功能: 本函数将完成对输入的图像信号按幻方置换策略进行置乱
% 输入格式举例: result = magicreplace( secretimage, 1, 1983)
% 参数说明:
% matrix 为输入图像矩阵
% key 为控制**
% eord 为 1 表示置乱变换, 为 0 表示复原变换
% result 为置乱后的结果
function result = magicreplace( matrix, eord, key)
% 分析原图像尺寸并补遗
[ m, n] = size( matrix) ;
rowadd = 11-mod( m, 11) ;
coladd = 11-mod( n, 11 ) ;
if rowadd == 11
rowadd = 0;
end
if coladd == 11
coladd = 0;
end
input = uint8( zeros( [ m + rowadd n + coladd] ) ) ;
input( 1∶m, 1∶n) = matrix;
% **生成随机数
rand( ′seed′, key) ;
control = randint( 1, 1 , [ 1 121] ) ;
% 11 阶标准幻方
magic =
[ 38 52 66 69 83 97 100 114 7 21 24 
  61 75 78 92 106 120 2 16 30 44 47
  84 98 101 115 8 22 25 39 53 56 70 
  107 121 3 17 31 34 48 62 76 79 93 
  9 12 26 40 54 57 71 85 99 102 116
  32 35 49 63 77 80 94 108 111 4 18 
  55 58 72 86 89 103 117 10 13 27 41
  67 81 95 109 112 5 19 33 36 50 64
  90 104 118 11 14 28 42 45 59 73 87
  113 6 20 23 37 51 65 68 82 96 110 
  15 29 43 46 60 74 88 91 105 119 1 ] ; 
if eord == 0
control = 121 -control;
elseif eord == 1
control = control;
else
error( ′输入参数错误′) ;
end
% 幻方变换主过程
for define = 1∶key% control
	for r = 1∶11
		for c = 1∶11
			magic( r, c) = magic( r, c) -1;
			if magic( r, c) == 0
					magic( r, c) = 121;
			end
		end
	end
end
% 查表置乱
fun = @replacemagicfun; % 调用子函数
result = blkproc( input, [ 11 11] , fun, magic) ;

( 2 ) 行列转换表子函数: replacemagicfun. m

% 11 阶幻方的行列查找表程序
function result = replacemagicfun( matrix, P1 )
% 初始化 11 阶幻方的行列查找表
row = [ 11 , 2, 4, 6, 8, 10, 1, 3, 5, 7, 9, 5, 7, 9, 11, 2, 4, 6 , 8, 10, 1 , 3, 10, 1 , 3, 5, 7, 9,
11, 2, 4, 6 , 8, 4, 6, 8, 10, 1, 3, 5, 7, 9 , 11, 2 , 9 , 11, 2, 4, 6, 8 , 10, 1, 3, 5 , 7, 3, 5, 7 , 9, 11 , 2,
4 , 6 , 8, 10 , 1, 8, 10 , 1, 3, 5, 7, 9, 11, 2, 4, 6 , 2 , 4 , 6, 8, 10, 1 , 3, 5, 7, 9, 11, 7, 9, 11, 2, 4 , 6,
8 , 10, 1, 3 , 5, 1, 3, 5, 7, 9, 11, 2, 4, 6 , 8, 10 , 6 , 8, 10 , 1, 3, 5, 7, 9, 11, 3, 4] ;
col = [ 11, 7, 3, 10, 6, 2, 9, 5, 1, 8, 4 , 2, 9, 5, 1, 8, 4, 11, 7, 3 , 10, 6, 4, 11, 7 , 3, 10 , 6,
2 , 9 , 5, 1, 8, 6, 2, 9, 5 , 1, 8, 4, 11, 7, 3, 10 , 8, 4, 11, 7 , 3, 10, 6, 2, 9, 5 , 1, 10, 6, 2 , 9, 5, 1,
8 , 4 , 11, 7 , 3, 1, 8, 4, 11, 7, 3, 10, 6, 2, 9, 5 , 3 , 10, 6, 2, 9, 5 , 1, 8, 4, 11 , 7, 5, 1, 8 , 4, 11 , 7,
3 , 10, 6, 2 , 9, 7, 3, 10, 6, 2, 9, 5, 1, 8 , 4, 11 , 9 , 5, 1, 8, 4, 11, 7, 3, 10, 6, 2] ;
for i = 1: 11
	for j = 1: 11
		result( i, j) = matrix( row( P1 ( i, j) ) , col( P1( i, j) ) ) ;
	end
end

3.图像的 Ha sh 置乱
前面的两种置乱都是对图像分块进行的, 而且其共同的问题是**控制并不得力。下面介绍的一种图像置乱方法实际上就是我们在 2. 6. 3 节中介绍的 Hash 置换的特例———对于 m× n 个像素点, 我们要求随机置换 m× n 个, 就完成了图像的 Hash置乱。鉴于该算法具有无冲突( collision) 和强**控制的特点, 显然是一个很好的图像置乱算法。需要说明的是, 这种算法不是对合的, 所以在实现上较前两种复杂一些。另外, 其算法执行起来也比较费时间。编写函数 hashdisturb. m 完成实验

% 文件名: hashdisturb. m
% 函数功能: 本函数将完成对输入的图像信号按 Hash 置换策略进行置乱
% 输入格式举例: result = hashdisturb( secretimage, 1, 1983 , 421, 1121)
% 参数说明:
% matrix 为输入图像矩阵
% key1 -key3 为控制**
% eord 为 1 表示置乱变换, 为 0 表示复原变换
% result 为置乱后的结果
function result = hashdisturb( matrix, eord, key1, key2, key3 )
% 分析原图像尺寸并补遗
[ m, n] = size( matrix) ;
% 调用随机置换函数
[ row, col] = hashreplacement( matrix, m* n, key1, key2, key3) ;
% 置乱函数
count = 1;
if eord == 1
	for i = 1∶m
		for j = 1∶n
			result( i, j) = matrix( row( count) , col( count) ) ;
			count = count + 1;
		end
	end
end
% 复原函数
if eord == 0
	for i = 1∶m
		for j = 1∶n
			result( row( count) , col( count) ) = matrix( i, j) ;
			count = count + 1;
		end
	end
end

4.隐藏置乱图像的优点
信息隐藏——第四章 图像信息隐藏数
经过多次置乱后, 图像就会彻底地改变, 从置乱后的图像上根本看不到原图像的任何特征。使用置乱方法为什么可以增加图像伪装的鲁棒性呢?
首先, 将图像置乱后, 将得到一幅杂乱无章的图像, 这个图像无色彩、无纹理、无形状, 从中无法读取任何信息, 那么, 将这样一幅图嵌入到另一幅普通图像时就不易引起那幅图色彩、纹理、形状的太大改变, 甚至不会发生改变, 这样人眼就不易识别,从而逃出了第三方的视线。

其次, 由于秘密图像是置乱后的图像, 根据上述图像的“三无”特征, 第三方根本不可能对其进行色彩、纹理、形状等的统计分析, 即便他们截取到了秘密图像, 也是无能为力的。如果第三者企图对秘密图像进行反置乱, 这也是不可能的, 由于图像置乱有很多种方法, 每种方法又可以使用不同的置乱模板算法, 设置不同的参数, 使用者有很大的*度, 他可以根据自己的想法得到不同的结果, 相反, 这给企图截获秘密信息的第三方带来了很大的困难, 使他们需要耗费巨大的计算量来穷举测试各种可能性

最后, 我们再设想一下, 如果第三方反置乱不成, 在隐蔽载体上恶意修改怎么办?通过实验我们知道, 用置乱的方法是可以抵抗这些攻击的, 因为对秘密图像进行反置换的过程, 就使得第三方在图像上所涂、画的信息分散到画面的各个地方, 形成了点状的随机噪声, 对视觉影响的程度不大。图 4. 20 是我们随意对隐蔽载体进行 3 种恶意攻击后提取的秘密图像内容。可以看到, 即使是在攻击 3 下, 秘密图像的轮廓依然可见, 这是在未置乱图像的隐藏下不可想像的。当然, 为了使提取的信息更为清晰,最好对破坏严重的图像进行边界保持的中值滤波等方面的处理, 以去除随机噪声。