一、A steganographic method for images by pixel-value differencing摘要
我们提出了一种新的、高效的隐写方法,用于将秘密信息嵌入灰度值的载体图像中。在嵌入秘密信息的过程中,载体图像被分割成两个连续像素的非重叠块。从每个区块中的两个像素的值计算出一个差值。所有可能的差值都被归入一些范围。范围区间的选择是基于人类视觉对灰度值变化的敏感性的特点,从平滑度到对比度。然后,差值被一个新的值所取代,以嵌入秘密信息的子流的值。一个像素对中可嵌入的比特数由差值所属的范围宽度决定。该方法的设计方式是,修改永远不会超出范围区间。这种方法提供了一种简单的方法,可以产生比简单的最低有效位替换方法更难以察觉的结果。嵌入的秘密信息可以从产生的隐写图像中提取出来,而不需要参考原始载体图像。此外,还可以使用伪随机机制来实现保密保护。实验结果显示了所提方法的可行性。还进行了双重统计攻击,以收集相关数据,显示该方法的安全性。
二、提出的方法
1、嵌入过程
提出的方法中使用的载体图像是256个灰度值的图像。一个差值d是从一个给定的载体图像的两个连续像素的每个非重叠块中计算出来的,比如pi和pi+1。将载体图像划分为双像素块的方式以之字形贯穿每幅图像的所有行,如下图所示。
假设pi和pi+1的灰度值分别为gi和gi+1,则d被计算为gi+1- gi,其范围可能在-255到255之间。d接近0的区块被认为是极其光滑的区块,而d接近-255或255的区块则被认为是边缘尖锐的区块。
根据对称性,我们只考虑d的可能绝对值(0到255),并将它们分为若干个连续的范围,比如Ri,其中i =1; 2; … ;n。这些范围被指定为索引1-n。Ri的下限和上限分别用li和ui表示,其中l1为0,un为255。Ri的宽度是ui- li +1。
在提出的方法中,每个范围的宽度都是2的幂,这种宽度的限制有利于嵌入二进制数据。选择的范围间隔是基于前面提到的人类视觉能力。代表平滑块的差值的范围的宽度被选择为较小,而代表边缘块的差值的范围被选择为较大。即当d接近0时,我们创建宽度较小的范围,当d远离0时,创建宽度较大的范围,以产生更好的不可察觉的结果。
一个落在索引为k的范围内的差值被称为索引为k。在某一范围内的所有数值(即所有具有相同索引的数值)被认为是足够接近的。即如果一个范围内的差值被同一范围内的另一个差值所取代,则这种变化估计不容易被人眼发现。在所提出的方法中,我们将秘密信息的一些比特嵌入到一个两像素的块中,方法是将该块的差值替换为具有相同索引的差值,即我们将一个范围内的差值换成另一个范围内的差值。换句话说,在提出的数据嵌入过程中,我们用两个新的灰度值来调整每个双像素对中的灰度值,这些灰度值的差异会导致隐写图像的观察者无法注意到的变化。
将比特流中的每一个比特嵌入到载体图像的双像素块中。可以被嵌入的比特数量块中的位数是不同的,由该块中两个像素的差值所属范围的宽度决定。给定一个索引为k、灰度值差为d的两像素块B,可嵌入该块的比特数,例如n,由n=log2(uk-lk+1)计算。由于每个范围的宽度被选择为2的幂,n=log2(uk-lk+1)的值是一个整数。接下来从秘密信息中选择一个有n个比特的子流S来嵌入B中。然后通过以下方式计算出一个新的差值d’:
其中b是子流S的值。因为b的值在0到uk-lk的范围内,所以d´的值在lk到uk的范围内。根据前面的讨论,若我们用d’替换d,所产生的变化对观察者来说大概是无法察觉的。然后,我们通过对d’进行逆向计算来嵌入b,产生新的灰度值(gi’, gi+1’),用于隐写图像中相应的两个像素块(pi’,pi+1’)的像素。当秘密信息的所有比特被嵌入时,即完成嵌入过程。从像素对的原始灰度值(gi,gi+1)计算(gi’,gi+1’)的逆向计算是基于一个函数f((gi,gi+1 ),m),被定义为:
其中m=d´-d,celingm=⌈m/2⌉,floorm=⌊m/2⌋。
在上述反演计算中,d’值越小则gi’和gi+1’区间越小,而d’值越大则gi’和gi+1’区间越大。因此,(gi, gi+1)可能产生无效的(gi’,gi+1’),即一些计算可能导致产生的gi’或gi+1脱离范围[0,255]的边界。尽管我们可以通过强制将脱离的边界值作为0和255的边界值之一,并将另一个值调整为适当的值以满足差值d’,从而将两个新值重新调整到[0, 255]的有效范围内,但在某些情况下,这可能会产生与周围区域对比的异常点。为了解决这个问题,我们采用了一个检查过程来检测这种脱离边界情况,并放弃产生这种情况的像素块进行数据嵌入。被放弃的块的灰度值在隐写的图像中保持不变。这一策略有助于我们在从隐写图像中恢复数据的过程中,很容易将有嵌入数据的块与被遗弃的块区分开来。值得注意的是,根据我们的实验,这种被遗弃的像素块在实际应用中是非常少的。
提出的脱离边界检查通过从函数f ((gi, gi+1), uk - d)值的逆向计算中产生一对(g^ i; g^ i+1)来进行。由于uk是lk到uk范围内的最大值,使用uk产生的一对(g^ i, g^ i+1)将产生最大的差值。即这个最大的范围区间g^ i+1-g^ i涵盖了其他(g^ i, g^ i+1)对产生的所有范围。故对区块的脱离边界检查可以只检查由使用uk的情况下产生的(g^ i,g^ i+1)的值来进行。如果g^ i+1或g^ i偏离了0或255的边界,我们认为该块有偏离的可能,并放弃该块的数据嵌入。
嵌入过程的具体实例如下:
具体解释:假设一个样本的双像素块的灰度值为(50,65)。差值为15,在8到23的范围内。范围的宽度是16=24,意味着范围内的一个差值可以用来嵌入四位的秘密数据。由公式2可知,本例中的差值d=15为奇数,则使用第一种情况,秘密信息的前四位二进制为1010,转换为十进制为b=10。由公式1可知,d=15>0,则d’=lk+b=8+10=18(注意不能混淆此处的lk是所选择范围的下限,不要以为是原灰度值的下限)。又原灰度值为(50,65),m=d’-d=18-15=3,则ceilingm=2,floorm=1,即新灰度值为(50-2,65+1)=(48,66)。
2、提取过程
提取嵌入信息的过程是通过使用伪随机方案的种子来产生与嵌入过程中相同的访问双像素块的遍历顺序来进行的。每次我们访问隐写图像中的一个两像素区块时,我们对该区块应用前面提到的相同的脱离边界检查,以找出该区块在嵌入过程中是否被使用过。假设隐写图像中的区块具有灰度值(gi* , gi+1*),并且两个灰度值的差值d* 具有索引k。我们通过使用f((gi*,gi+1*), uk -d*)对(gi*,gi+1*)应用脱离边界检查过程。
若两个值(g^ *i,g^*i+1)都没有脱离边界,意味着有一些数据被嵌入到这个块中。嵌入在这个两像素块中的值b,然后可以使用以下公式提取出来:
三、matlab代码复现
1、PVD.m
clc;
close all;
clear;
%%%%%%%%%%%%%%%%%%%%%%%读取秘密信息文件%%%%%%%%%%%%%%%%%%%%%%%%
file_id = fopen('message.txt','r');% file_id=fopen(filename,permission)将打开由permission指定访问类型的文件,permission可以取'r'(打开要读取的文件)、'w'(打开或创建要写入的文件)'等
file_content = fread(file_id); % A=fread(file_id) 将打开的二进制文件中的数据读取到列向量A中,并将文件指针定位在文件结尾标记处
file_length = length(file_content);% y=length(x)函数计算指定向量或矩阵的长度y,此处是计算秘密信息文件的长度
in = [];
in = [in dec2bin(file_length,20)]; % binStr = dec2bin(D,minDigits)将十进制数转换为以二进制数表示的字符数组(D可以用少于minDigits位的二进制位来表示,则dec2bin会用前导零填充输出;D 太大,必须用超过minDigits的位来表示,则dec2bin将用所需位数返回输出)
for i=1:file_length
in=[in dec2bin(file_content(i),7)];
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%嵌入过程%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
cover_image = rgb2gray(imread('cover_image.bmp')); % 将RGB图像转为灰度图像
[r,c] = size(cover_image);
final = double(cover_image);
next=0;
capacity=0; % 初始化嵌入容量
for x=0:1:r-1
for y=0:2:c-1 % 要求对一对像素值同时进行操作,故对于列要以间隔为2进行遍历
enable = 1; % enable是一个标志位,当发现像素值脱离边界时令enable=0
p = double(cover_image(1+x,1+y:2+y)); % 两个连续像素块,pi & pi+1
d = p(1,2) - p(1,1); % 两个连续像素的差且取其绝对值(注意不能单纯认为p(1,1)是第一个像素,p(1,2)是第二个像素,此处的p(1,1)和p(1,2)是指每含有两个像素的块对应的像素值)
d_abs=abs(d);
% 文章中第一个实验是基于选择8、8、16、32、64和128的范围宽度,将[0,255]划分为[0,7]、[8,15]、[16,31]、...、[128,255]
lb=[0 8 16 32 64 128]; % Ri的下限
ub=[7 15 31 63 127 255]; % Ri的上限
for i=1:1:6 % 测试Ri的边界(注意一共分为6个范围)
if((d_abs >= lb(i)) && (d_abs <= ub(i))) % 选择范围
% 检查一个像素块中是否有任何像素脱离边界[0,255]
even2 = mod(d,2);
m2 = ub(i) - d; % 公式2中对于m=d'-d
% 根据公式2所得
if (even2 == 0) % 偶数
Pcheck=[p(1,1)-floor(m2/2) p(1,2)+ceil(m2/2)];
else % 奇数
Pcheck=[p(1,1)-ceil(m2/2) p(1,2)+floor(m2/2)];
end
if(Pcheck(1)<0 || Pcheck(2)<0 || Pcheck(1)>255 || Pcheck(2)>255) % 像素值越界将enable置为0,即文章中对应的检查过程,对有嵌入数据的块和被遗弃的块用enable区分开
enable = 0;
break
end
n = ub(i)-lb(i)+1; % Ri的宽度
t = floor(log2(n)); % 两个连续像素块中可以嵌入的最大容量(注意最好带上向下去取整)
capacity=capacity+t; % 计算封面图像可以嵌入的秘密信息的最大容量
% 检查next是否超过message的长度
if(next>length(in))
m=0;
% 检查next+t是否超过message的长度
elseif(next+t>length(in))
if(1+next>=length(in))
k=zeros(1,t);
else
k=in(1+next:length(in));
end
diff =next+t-length(in);
k1=zeros(1,t);
if(diff>0)
for j=1:next+t-length(in)
k1(j)=k(j);
end
end
k=k1;
next=next+t;
k=bin2dec(char(k));
if(1+next>length(in))
m=0;
else
% 根据公式1所得
if(d >= 0)
dnew = k + lb(i);
else
dnew = -(k + lb(i));
end
m = dnew - d;% 根据公式2定义
end
% 若next的值小于message的值
else
k=in(1+next:t+next);
next=next+t;
k=bin2dec(char(k));
% 根据公式1所得
if(d >= 0)
dnew = k + lb(i);
else
dnew = -(k + lb(i));
end
m = dnew - d;% 根据公式2定义
end
end
end
% 上面进行此操作主要是为了检查是否有像素脱离边界,此处进行此操作是为了从原始的双像素值产生新的双像素值
% 此处对应文章中说明区分有嵌入数据的块和被遗弃的块
if (enable == 1)
even = mod(d,2);
if (even == 0)
P0=[p(1,1)-floor(m/2) p(1,2)+ceil(m/2)];
else
P0=[p(1,1)-ceil(m/2) p(1,2)+floor(m/2)];
end
final(1+x,1+y)=P0(1,1);
final(1+x,2+y)=P0(1,2);
end
end
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%生成隐写图像%%%%%%%%%%%%%%%%%%%%%%%%%%
if(next>length(in))
disp('Message Embedded Successfully');
stego_image=uint8(final); % 将double类型的图像转为uint8类型便于显示
imwrite(stego_image,'stego_image.bmp'); % imwrite函数将图像写入图形文件,调用格式为imwrite(A,filename)
fclose('all');
else % 检查所要嵌入的消息的封面图像是否太小
error('Cover Image is too small for the given messege to be embedded, please replace cover image with the larger one.');
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%提取过程%%%%%%%%%%%%%%%%%%%%%%%%%%%%
clc;
clear all;
stego_image = imread('stego_image.bmp');
[r,c]=size(stego_image);
j=0;
msg = [];% 初始化需要提取的秘密信息
flag = 0;
length=0;
enable = 1;
for x=0:1:r-1
for y=0:2:c-1
if (enable == 1) % 当任何像素脱离边界时会使enable=0
gp = double(stego_image(1+x,1+y:2+y)); % 两个连续像素块,pi & pi+1
d = gp(1,2) - gp(1,1); % 两个连续像素的差且取其绝对值(注意不能单纯认为p(1,1)是第一个像素,p(1,2)是第二个像素,此处的p(1,1)和p(1,2)是指每含有两个像素的块对应的像素值)
nd = abs(d);
lb = [0 8 16 32 64 128]; % Ri的下限
ub = [7 15 31 63 127 255]; % Ri的上限
for i=1:1:6 % 测试Ri的边界(注意一共分为6个范围)
if(nd>=lb(i)&&nd<=ub(i))
% 检查一个像素块中是否有任何像素脱离边界[0,255]
even2 = mod(d,2);
m2 = ub(i) - d;
if (even2 == 0)
Pcheck=[gp(1,1)-floor(m2/2) gp(1,2)+ceil(m2/2)];
else
Pcheck=[gp(1,1)-ceil(m2/2) gp(1,2)+floor(m2/2)];
end
if(Pcheck(1)<0 || Pcheck(2)<0 || Pcheck(1)>255 || Pcheck(2)>255)
break
end
w = ub(i)-lb(i)+1; % Ri的宽度
t=log2(w); % 可以在宽度为w中嵌入的秘密信息比特
b = nd - lb(i);
k=dec2bin(b,t);
msg = [msg k];
j=j+t;
if(flag==0 && j>=20)
length=bin2dec(msg(1:20))+3;
length=length*7;
flag=1;
end
if(flag==1 && j>=length)
j=1;
for i=20:7:length-7
finaltxt(j)=bin2dec(msg(1+i:7+i));
j=j+1;
end
fid=fopen('output.txt','w');
fwrite(fid,finaltxt); % fwrite函数将数据写入二进制文件,调用格式为fwrite(fileID,A)
disp('Message Extracted Successfully');
fclose('all'); % 完成写入后,请调用fclose(fileID) 来关闭文件
enable = 0;
end
end
end
end
end
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
subplot(121),imshow('cover_image.bmp');
title('原始图像');
subplot(122),imshow('stego_image.bmp');
title('隐写图像');
2、test.m
cover_image=rgb2gray(imread('cover_image.bmp'));
stego_image=imread('stego_image.bmp');
[M,N]=size(cover_image);
B=8; % 编码一个像素用多少二进制位
MAX=2^B-1; % 图像有多少灰度级
MES=sum(sum((cover_image-stego_image).^2))/(M*N); % 均方差
PSNR=20*log10(MAX/sqrt(MES)); % 峰值信噪比
fprintf ('峰值信噪比是: % f\n' ,PSNR);
3、实现展示
2、test.m
峰值信噪比是: 74.204178
message.txt中的内容(即为文章摘要):
A steganographic method for images by pixel-value differencing
A new and efficient steganographic method for embedding secret messages into a gray-valued cover image is proposed. In the process of embedding a secret message, a cover image is partitioned into non-overlapping blocks of two
consecutive pixels. A difference value is calculated from the values of the two pixels in each block. All possible difference
values are classified into a number of ranges. The selection of the range intervals is based on the characteristics of
human vision s sensitivity to gray value variations from smoothness to contrast. The difference value then is replaced by
a new value to embed the value of a sub-stream of the secret message. The number of bits which can be embedded in a
pixel pair is decided by the width of the range that the difference value belongs to. The method is designed in such a way
that the modification is never out of the range interval. This method provides an easy way to produce a more imperceptible result than those yielded by simple least-significant-bit replacement methods. The embedded secret message
can be extracted from the resulting stego-image without referencing the original cover image. Moreover, a pseudorandom mechanism may be used to achieve secrecy protection. Experimental results show the feasibility of the proposed
method. Dual statistics attacks were also conducted to collect related data to show the security of the method.
PS:因为大佬复现的论文代码还有很多地方看不懂,此处就不班门弄斧,后面有时间再好好想想如何实现成功。
论文网址:
A steganographic method for images by pixel-value differencing