空域图像信息隐藏

空域图像信息隐藏

一、LSB算法

【实验目的】

了解信息隐藏中常用的LSB算法,并掌握其原理,设计并实现基于图像LSB隐藏算法,并通过峰值信噪比(PSNR)对图像质量进行评价,对结果进行卡方分析和RS分析。

【实验环境】

matlab/python *灰度图片* s-tool工具

【实验原理】

1) 图像

灰度图:使用一个0(全黑)~255(全白)的数字表示一个像素点的灰度等级。

RGB图像:由三个通道组成,每个像素点上由一组数据【B(蓝色) G(绿色) R(红色)】表示,同样的表示单一颜色通道的值取值范围也为0~255。

(2)位深度:以灰度图为例,每一个像素点上有一个8位二进制串(0-255)表示灰度值,灰度层的位深度就为8。

(3)位层:以灰度图为例,每个像素点的每一位组成一个位层,如每个像素点的最低位组成最低位层,最高位组成最高位层,灰度图片一共有8个位层,因为每一个像素点由8位组成。

任务:

1) 选取合适的图片作为载体图片和嵌入图片,载体图片分成8个位平面,并显示。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
I=imread("./**.bmp");      %载体图片

[h,w]=size(I);

II=zeros(h,w,8);

a=I; %存储原始图像矩阵

for k=1:8

II(:,:,k) = mod(a,2);%将图像灰度值分解为二进制串,然后取第k位

a=idivide(int32(a),int32(2));

subplot(3,3,k+1);

imshow(II(:,:,k));

tex=['第',num2str(k),'个位平面'];

title(tex);

end

2) 制作水印图片,分别为一个位平面的,两个位平面的,三个位平面的,并显示,将制作的水印图片嵌入载体图片中生成含水印图片并显示。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
for k=1:3

II(:,:,k)=II0(:,:,9-k); %替换后三位的数据

for kk=8:-1:1

​ III(:,:,k)=III(:,:,k)*2+II(:,:,kk);

end

subplot(2,2,k+1);

imshow(III(:,:,k),[]);

tex=['嵌入',num2str(k),'bit/pixel后的伪装图片'];

title(tex);

end

3) 从含水印图片中提取水印图片并显示,对含水印图片进行信噪比计算(PSNR)

img

4) 比较含水印图片和原图的直方图,

5) 使用stirmark进行攻击,并分析结果

【实验过程】

  1. 将载体图片分成8个位平面。

img

  1. 制作水印图片,分别为一个位平面的,两个位平面的,三个位平面的,将制作的水印图片嵌入载体图片中生成含水印图片并显示。

img

img

  1. 从含水印图片中提取水印图片并显示,对含水印图片进行信噪比计算(PSNR)

img

Psnr=11.9784

img

  1. 比较含原图和水印图片的直方图

imgimg

  1. 使用stirmark进行攻击,并分析结果

img

旋转0.25

img

旋转5

img

旋转45

img

综上可看出,经过旋转攻击后,水印模糊。

【代码】

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
一、
clc
clear
close all
I=imread("./pic.bmp"); %载体图片
I0=imread("./lena.bmp"); %被嵌入图片
figure()
[h,w]=size(I);
subplot(3,3,1);
imshow(I);
title("原图");
II=zeros(h,w,8);
II0=zeros(h,w,8);
%% 将载体图片分成8个位平面,并显示
a=I; %存储原始图像矩阵
for k=1:8
II(:,:,k) = mod(a,2);%将图像灰度值分解为二进制串,然后取第k位
a=idivide(int32(a),int32(2));
subplot(3,3,k+1);
imshow(II(:,:,k));
tex=['第',num2str(k),'个位平面'];
title(tex);
end
%% 制作水印图片
a=I0;
for k=1:8
II0(:,:,k) = mod(a,2);%将图像灰度值分解为二进制串,然后取第k位
a=idivide(int32(a),int32(2));
end
figure();
A=zeros(h,w); %制作水印图片,可以嵌入1个位平面的、2个位平面的、3个位平面的
subplot(2,2,1);
imshow(I0);
title("原图");
for i=1:3
P=A;
P(:,:)=P(:,:)*2+II0(:,:,9-i);
A=P;
P=bitshift(P,8-i);
subplot(2,2,i+1);
imshow(P,[]);
tex=['嵌入',num2str(i),'个位平面的水印图片'];
title(tex);
end
%% 图片开始嵌入载体图片并显示载体图像
figure();
subplot(2,2,1)
imshow(I);
title("原图");
III=zeros(h,w,3); %分别嵌入1bit/pixel、2bit/pixel、3bit/pixel后的伪装图片
for k=1:3
II(:,:,k)=II0(:,:,9-k); %替换后三位的数据
for kk=8:-1:1
III(:,:,k)=III(:,:,k)*2+II(:,:,kk);
end
subplot(2,2,k+1);
imshow(III(:,:,k),[]);
tex=['嵌入',num2str(k),'bit/pixel后的伪装图片'];
title(tex);
end
imwrite(uint8(III(:,:,3)),'result.bmp');
%% 嵌入图片提取
figure();
III0=zeros(h,w,3); %分别保存三个维度的替换后的水印图片(取前3位)
for i=1:3
a=int32(III(:,:,i));
subplot(3,2,2*(i-1)+1);
imshow(a,[]);
tex=['嵌入',num2str(i),'bit/pixel后的伪装图片'];
title(tex);
IIII=zeros(h,w);
for k=1:i
III0(:,:,k)=mod(a,2);%将图像灰度值分解为二进制串,然后取第k位
a=idivide(int32(a),int32(2));
IIII(:,:)=IIII(:,:)*2+III0(:,:,k);
end
IIII=bitshift(IIII,8-i);
subplot(3,2,2*(i-1)+2);
imshow(IIII,[]);
tex=['嵌入',num2str(i),'bit/pixel后的秘密信息提取'];
title(tex);

end

二、二值图像信息隐藏

【实验目的】

了解二值图像的基本特点,并在二值图片中嵌入隐藏信息。

【实验环境】

matlab/python

【实验原理】

第一种方法:把一个二值图像分成L个矩形图像区域Bi ,如果Bi中黑色象素的个数大于一半,则表示嵌入0;如果白色象素的个数大于一半,则表示嵌入1,当需要嵌入的比特与所选区域的黑白象素的比例不一致时,为了达到希望的象素关系,则需要修改一些象素的颜色。修改应遵循一定的规则,原则是不引起感观察觉。修改应在黑白区域的边缘进行。同时为了保证修改的区域不大,保证图片的质量,对修改的块Bi应该做出选择,当需要修改太多时,应该选择放弃从而选取其他块。所以,应考虑有一定的冗余度。确定有效区域。确定两个阈值 R1 > 50% 和 R0 < 50% ,以及一个健壮性参数 λ 。隐藏 0 时,该块的黑色象素的个数应属于 [R1 , R1 + λ] 隐藏 1 时,该块的黑色象素的个数应属于 [R0 - λ , R0] 。如果为了适应所嵌入的比特,目标块必须修改太多的象素,就把该块设为无效。标识无效块:将无效块中的象素进行少量的修改,使得其中黑色象素的百分比大于 R1 + 3λ ,或者小于 R0 - 3λ 。

第二种方法:利用游标卡尺方法,例:

img

编码:< a0, 3 > < a1, 5 > < a2, 4 > < a3, 2 > < a4, 1 >,如果秘密信息位是 0 ,则修改该游程长度为偶数;如果为 1 ,则修改游程长度为奇数;上面便可以嵌入(11001)五位编码

任务:

完成第一或者第二种方法,并从嵌入的图片中成功提取水印,附上代码和截图。并用stirmark攻击对水印进行鲁棒性测试

【实验过程】

第二种方法:

  1. 隐藏信息

img原图与水印图片

img img

​ 原图 水印图

  1. 信息提取

img

  1. stirmark攻击

Stirmark不能对本实验所用bmp单色位图进行攻击产生结果,无法测试。

【代码】

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126

二、
嵌入
clc;
clear;

threshold = 10;
oi = imread('lena2.bmp');
si = size(oi); % 保存读入图像的行列,以便恢复图像
oi = oi(:); % 变成一列, 按列变
[len, col] = size(oi); %len= row,1
carrier = oi;

j=1;
i=1;
%统计游程长度
while(i <= len)
last = oi(i); % 依次取出每个数
count = 1;
while( i+1 <= len && oi(i+1)== last) % 下一个与上一个相同
i = i + 1;
count = count + 1;
end
RLE(j) = count;
j = j + 1;
i = i + 1;
end

msgfid = fopen('hide.txt', 'r');
[msg, msgcount] = fread(msgfid);
fclose(msgfid);

msg = dec2bin(msg,8); %将读入的每个字节转换成二进制
msg = str2num(msg(:)); %
msgcount = msgcount*8; % 需要隐藏的数目

i = 1; % msg 的索引
count = 1; % RLE的索引,只为奇数 1 3 5...
sum = 0;
while count < length(RLE)-1
addSum = RLE(count) + RLE(count+1); %相邻两个数相加的和,从1开始
if count >= 3
sum = sum + RLE(count - 1) + RLE(count - 2); % 当前count的在数组中的下标-1
end
if(addSum >= threshold) % 只有当相邻游程和大于阈值,才隐藏信息
if RLE(count) >= RLE(count+1)
modifyPoint = sum + RLE(count);
else
modifyPoint = sum + RLE(count) + 1;
end
if(msg(i) == 0) % 嵌入的信息为0,但是游程为奇数,需要修改
if(mod(RLE(count), 2) == 1) %RLE(count) == '奇数'
carrier(modifyPoint) = mod(carrier(modifyPoint)+1 ,2); % 修改点的值取反 mod(carrier(modifyPoint)+1 ,2)
end
else % 嵌入的信息为1,但是游程为偶数,需要修改
if mod(RLE(count), 2) == 0 %RLE(count) == '偶数'
carrier(modifyPoint) = mod(carrier(modifyPoint) + 1 ,2); % 修改点的值取反 mod(carrier(modifyPoint)+1 ,2)
end
end
i = i + 1; % 隐藏一个位后, msg索引加1
end
count = count + 2;
if i == msgcount
break;
end
end

if i < msgcount
error('不能隐藏全部信息!');
end

imwrite(reshape(carrier, si(1),si(2),[]), 'hide.bmp');
figure;
subplot(121);
imshow(reshape(oi, si(1),si(2),[]));
title('原图');
subplot(122);
imshow('hide.bmp');
title('水印图');

提取
clc;
clear;

threshold = 3;
oi = imread('hide.bmp');
oi = oi(:); % 变成一列, 按列变
[len, col] = size(oi); %len= row,1

j=1;
i=1;
%统计游程长度
while(i <= len)
last = oi(i); % 依次取出每个数
count = 1;
while( i+1 <= len && oi(i+1)== last) % 下一个与上一个相同
i = i + 1;
count = count + 1;
end
RLE(j) = count;
j = j + 1;
i = i + 1;
end

i = 1;
msgcount = 160;
msg = zeros(msgcount,1);
count = 1; % RLE的索引,只为奇数 1 3 5...
while i <= msgcount
addSum = RLE(count) + RLE(count+1); %相邻两个数相加的和,从1开始
if(addSum >= threshold) % 只有当相邻游程和大于阈值,才隐藏信息
if mod(RLE(count),2) == 0
msg(i) = 0;
else
msg(i) = 1;
end
i = i + 1;
end
count = count + 2;
end

hideInfo = reshape(msg,length(msg)/8,8); %将二进制字符串分成n行,8列
bin = num2str(hideInfo); % 二进制数值转变成二进制字符串
dec = bin2dec(bin);%二进制字符串转换成十进制数组
recoverdata = native2unicode(dec);% 本机编码转换成unicode
fprintf('恢复出的信息:%s\n',recoverdata);

三、patchwork图像信息隐藏

【实验目的】

了解Patchwork信息隐藏特点,掌握基于Patchwork的图像信息隐藏原理,设计并实现

【实验环境】

matlab/python

【实验原理】

Patchwork是指从载体数据中选择一些数据组成两个集合,然后通过修改这两个集合之间的某种关系来携带水印信息。这两个集合可以是两个系数、两组系数或者是两个特征量。两个集合之间的关系可以是大小关系、能量关系、逻辑关系和奇偶性关系等。

Patchwork方法嵌入水印时,通过修改集合之间的某种关系来嵌入水印;提取水印时,则根据对应的关系来提取嵌入的水印信息。Patchwork方法最大优点之一就是可以实现盲检测。Patchwork适用于时/空域、变换域和压缩域,本节主要介绍时域下的典型Patchwork方法。

Patchwork方法典型算法只能隐藏lbit的信息,即只能说明该图像是否存在水印,隐藏的信息量比较小,但是该算法的鲁棒性较强。该算法的原理如下:随机选择两个集合A={ai}和B={bi},要求A和B中含有相同图像系数,设为n;将集合A中所有样点的像素值增加d,同时将集合B中所有样点的像素值减少d,这样两个集合中的样值都经过微小的改动。选择集合A和B的方法很多,但是Patch Work方法是基于以下假设的,也就是说随机选择的两个样本集合的均值相同。本节中方法是根据图像的横坐标和纵坐标之和的奇偶性不同将图像分为两组,将横坐标和纵坐标之和为偶数的所有系数上增加常量d=2.3,将横坐标和纵坐标之和为奇数的所有系数上减少常量d=2.3。另一种方法是随机选择N对像素点(ai和bi),然后将ai点的数值增加d,将bi点的像素值减少d。

要求:

完成嵌入和提取方法,用stirmark进行攻击测试,查看鲁棒性,并分析结果。

Tips:嵌入

for i=1:row

for j=1:col

​ if mod(i+j,2)==0

​ wi(i,j)=wi(i,j)+d;

​ else

​ wi(i,j)=wi(i,j)-d;

​ end

end

end

提取

提取时,首先将两个图像块集合的样本分别求平均值,计算两个样本均值的差来判断水印信息是否存在

wi=imread(lenawatermarked.bmp’);%读入载体图像

wi=double(wi);%必须将unit8类型转换成为double类型,否则tempa也是unit8的类型,最大值只能存储255

tempa=0;

tempb =0;

for i=1:row

for j=1:col

​ if mod(i+j,2)==0

​ tempa=tempa +wi(i,j);

​ else

​ tempb=tempb+ wi(i,j);

​ end

end

end

【实验过程】

  1. 嵌入

img

  1. 提取

img

Watermark=1,图片隐藏水印

  1. Stirmark攻击

img

水印图像经过crop攻击后仍能被检测出水印,说明patchwork算法得到的图像抗裁剪攻击。

【代码】

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
三、
嵌入
clc;
clear;
oi=imread('lena.bmp');
wi=oi;
wi=double(wi);
[row,col]=size(wi);
d=2.3;
for i=1:row
for j=1:col
if mod(i+j,2)==0
wi(i,j)=wi(i,j)+d;
else
wi(i,j)=wi(i,j)-d;
end
end
end
imwrite(uint8(wi),'hide.bmp');
subplot(2,2,1),imshow('lena.bmp'),title('原始图像');
subplot(2,2,2),imshow('hide.bmp'),title('水印图像');

提取
clc;
clear;
d=2.3;
r=1.6;
wi=imread('hide_CROP_10.bmp');%读入载体图像
wi=double(wi);%必须将unit8类型转换成为double类型,否则tempa也是unit8的类型,最大值只能存储255
[row,col]=size(wi);
tempa=0;
tempb =0;
for i=1:row
for j=1:col
if mod(i+j,2)==0
tempa=tempa +wi(i,j);
else
tempb=tempb+ wi(i,j);
end
end
end
avea=(tempa*2)/(row*col);
aveb=(tempb*2)/(row*col);
if(avea-aveb)>r*d
watermark=1;
else
watermark=0;
end


空域图像信息隐藏
http://example.com/2022/12/30/空域图像信息隐藏/
作者
Magnesium
发布于
2022年12月30日
许可协议