像素预测–求预测值px:
比特位对比–生成像素位图:
将原像素x和预测误差px转换为8位二进制,然后从高位到低位逐位比较,相同的比特数目即为该像素点的标记。
图像加密:通过加密密钥生成一个和图像大小相同的随机矩阵,将原始图像和随机矩阵进行bit异或加密,得到加密图像。
哈夫曼编码标记:9个哈夫曼编码:00;01;100;101;1100;1101;1110;11110;11111
规则:用较短的编码来标记较多的像素。
Map即为转换过后的位图,根据哈夫曼编码规则建立编码和像素之间的映射关系
取相同的位是因为相同的位直接可以根据位图还原,而第一个不同位取反也能恢复原图,所以可多取一位。
由于编码的映射关系也需要存储,所以这时就体现出了高频低比特的好处,可嵌入位的净增加值得到了提升
其中(32+20)表示哈夫曼编码映射关系和标记图的长度信息。
主函数:
clear
clc
I = imread('Airplane.tiff');
origin_I = double(I); %double(I)是将读入的图像I的uint8数据转换为double类型的数据
%% 产生二进制秘密数据
num = 10000;
rand('seed',0); %设置种子
D = round(rand(1,num)*1); %产生稳定随机数
%% 使用图片代替随机数据
% J = imread('Jetplane.tiff');
% D = dec2bin(J);%将待嵌入数据转换成二进制形式
% D = strcat(char(D)', '');%将其转换成字符数组
% D = str2num(D(:));%将其转换成整数数组
% num=numel(D);%统计待嵌入数据总长度
%% 设置图像加密密钥及数据加密密钥
Image_key = 1;
Data_key = 2;
%% 设置参数(方便实验修改)
ref_x = 1; %用来作为参考像素的行数
ref_y = 1; %用来作为参考像素的列数
%% 图像加密及数据嵌入
[encrypt_I,stego_I,emD] = Encrypt_Embed(origin_I,D,Image_key,Data_key,ref_x,ref_y);
%% 数据提取及图像恢复
num_emD = length(emD);
if num_emD > 0 %表示有空间嵌入数据
%--------在加密标记图像中提取信息--------%
[Side_Information,Refer_Value,Encrypt_exD,Map_I,sign] = Extract_Data(stego_I,num,ref_x,ref_y);
if sign == 1 %表示能完全提取辅助信息
%---------------数据解密----------------%
[exD] = Encrypt_Data(Encrypt_exD,Data_key);
%---------------图像恢复----------------%
[recover_I] = Recover_Image(stego_I,Image_key,Side_Information,Refer_Value,Map_I,num,ref_x,ref_y);
%---------------图像对比----------------%
figure;
subplot(221);imshow(origin_I,[]);title('原始图像');
subplot(222);imshow(encrypt_I,[]);title('加密图像');
subplot(223);imshow(stego_I,[]);title('载密图像');
subplot(224);imshow(recover_I,[]);title('恢复图像');
%---------------结果记录----------------%
[m,n] = size(origin_I);
bpp = num_emD/(m*n);
%---------------结果判断----------------%
check1 = isequal(emD,exD);
check2 = isequal(origin_I,recover_I);
if check1 == 1
disp('提取数据与嵌入数据完全相同!')
else
disp('Warning!数据提取错误!')
end
if check2 == 1
disp('重构图像与原始图像完全相同!')
else
disp('Warning!图像重构错误!')
end
%---------------结果输出----------------%
if check1 == 1 && check2 == 1
disp(['嵌入容量为 : ' num2str(num_emD)])
disp(['嵌入率为 : ' num2str(bpp)])
fprintf(['该测试图像------------ OK','\n\n']);
else
fprintf(['该测试图像------------ ERROR','\n\n']);
end
else
disp('无法提取全部辅助信息!')
fprintf(['该测试图像------------ ERROR','\n\n']);
end
else
disp('辅助信息大于总嵌入量,导致无法存储数据!')
fprintf(['该测试图像------------ ERROR','\n\n']);
end
二进制转十进制:
function [value] = Binary_Decimalism(bin2_8)
% 函数说明:将二进制数组转换成十进制整数
% 输出:bin2_8(二进制数组)
% 输入:value(十进制整数)
value = 0;
len = length(bin2_8);
for i=1:len
value = value + bin2_8(i)*(2^(len-i));
end
十进制转二进制:
function [bin2_8] = Decimalism_Binary(value)
% 函数说明:将十进制灰度像素值转换成8位二进制数组
% 输入:value(十进制灰度像素值)
% 输出:bin2_8(8位二进制数组)
bin2_8 = dec2bin(value)-'0';
if length(bin2_8) < 8
len = length(bin2_8);
B = bin2_8;
bin2_8 = zeros(1,8);
for i=1:len
bin2_8(8-len+i) = B(i); %不足8位前面补充0
end
end
预测误差:
function [origin_PV_I] = Predictor_Value(origin_I,ref_x,ref_y)
% 函数说明:计算origin_I的预测值
% 输入:origin_I(原始图像),ref_x,ref_y(参考像素的行列数)
% 输出:origin_PV_I(原始图像的预测值)
[row,col] = size(origin_I); %计算origin_I的行列值
origin_PV_I = origin_I; %构建存储origin_I预测值的容器
for i=ref_x+1:row %前ref_x行作为参考像素,不用预测
for j=ref_y+1:col %前ref_y列作为参考像素,不用预测
a = origin_I(i-1,j);
b = origin_I(i-1,j-1);
c = origin_I(i,j-1);
if b <= min(a,c)
origin_PV_I(i,j) = max(a,c);
elseif b >= max(a,c)
origin_PV_I(i,j) = min(a,c);
else
origin_PV_I(i,j) = a + c - b;
end
end
end
图像异或加密:
function [encrypt_I] = Encrypt_Image(origin_I,Image_key)
% 函数说明:对图像origin_I进行bit级异或加密
% 输入:origin_I(原始图像),Image_key(图像加密密钥)
% 输出:encrypt_I(加密图像)
[row,col] = size(origin_I); %计算origin_I的行列值
encrypt_I = origin_I; %构建存储加密图像的容器
%% 根据密钥生成与origin_I大小相同的随机矩阵
rand('seed',Image_key); %设置种子
E = round(rand(row,col)*255); %随机生成row*col矩阵
%% 根据E对图像origin_I进行bit级加密
for i=1:row
for j=1:col
encrypt_I(i,j) = bitxor(origin_I(i,j),E(i,j));
end
end
end
信息异或加密:
function [Encrypt_D] = Encrypt_Data(D,Data_key)
% 函数说明:对原始秘密信息D进行bit级异或加密
% 输入:D(原始秘密信息),Data_key(数据加密密钥)
% 输出:Encrypt_D(加密的秘密信息)
num_D = length(D); %求嵌入数据D的长度
Encrypt_D = D; %构建存储加密秘密信息的容器
%% 根据密钥生成与D长度相同的随机0/1序列
rand('seed',Data_key); %设置种子
E = round(rand(1,num_D)*1); %随机生成长度为num_D的0/1序列
%% 根据E对原始秘密信息D进行异或加密
for i=1:num_D
Encrypt_D(i) = bitxor(D(i),E(i));
end
end
位图标记:
function [Map_origin_I] = Category_Mark(origin_PV_I,origin_I,ref_x,ref_y)
% 函数说明:对每个像素值进行标记,即生成原始图像的位图
% 输入:origin_PV_I(预测值),origin_I(原始值),ref_x,ref_y(参考像素的行列数)
% 输出:Map_origin_I(像素值的标记分类,即位置图)
[row,col] = size(origin_I); %计算origin_I的行列值
Map_origin_I = origin_I; %构建存储origin_I标记的容器
for i=1:row
for j=1:col
if i<=ref_x || j<=ref_y %前ref_x行、前ref_y列作为参考像素,不标记
Map_origin_I(i,j) = -1; %标记为-1是为了与下面产生的t=7时ca=0情况分开,两种情况都不能嵌入数据,但是参考像素不必恢复,非参考像素需要在恢复操作中被遍历
else
x = origin_I(i,j); %原始值
pv = origin_PV_I(i,j); %预测值
for t=7:-1:0
if floor(x/(2^t)) ~= floor(pv/(2^t)) % floor(x) 函数向下取整
ca = 8-t-1; %用来记录像素值的标记类别 -1是因为不同的那一位也可以嵌入数据
break;
else
ca = 8;
end
end
Map_origin_I(i,j) = ca; %表示有ca位MSB相同,即可以嵌入ca位信息
end
end
end
位图转化为二进制数组:
function [Map_Bin] = Map_Binary(Map_origin_I,Code)
% 函数说明:将位图Map_origin_I转换成二进制数组Map
% 输入:Map_origin_I(原始图像的位置图),Code(映射关系)
% 输出:Map_Bin(原始图像位置图的二进制数组)
[row,col] = size(Map_origin_I); %计算Map_origin_II的行列值
Map_Bin = zeros();
t = 0; %计数,二进制数组的长度
for i=1:row
for j=1:col
if Map_origin_I(i,j) == -1 %标为-1的点是作为参考像素,不统计
continue;
end
for k=1:9
if Map_origin_I(i,j) == Code(k,1)
value = Code(k,2);
break;
end
end
if value == 0
Map_Bin(t+1) = 0;
Map_Bin(t+2) = 0;
t = t+2;
elseif value == 1
Map_Bin(t+1) = 0;
Map_Bin(t+2) = 1;
t = t+2;
else
add = ceil(log2(value+1)); %表示标记编码的长度
Map_Bin(t+1:t+add) = dec2bin(value)-'0'; %将value转换成二进制数组
t = t + add;
end
end
end
哈夫曼编码:
function [Code,Code_Bin] = Huffman_Code(num_Map_origin_I)
% 函数说明:用变长编码(多位0/1编码)表示像素值的标记类别
% 输入:num_Map_origin_I(像素值标记类别的统计情况)
% 输出:Code(映射关系),Code_Bin(Code的二进制表示)
% 备注:用{00,01,100,101,1100,1101,1110,11110,11111}这9中编码来表示9种标记类别
% 规则:标记类别中像素的个数越多,则用来表示其类别的编码长度越短
% {00,01,100,101,1100,1101,1110,11110,11111}→{0,1,4,5,12,13,14,30,31}
%% 求其映射编码关系
%Code = [-1,0;-1,1;-1,4;-1,5;-1,12;-1,13;-1,14;-1,30;-1,31];
%此处的-1仅有一个标记作用,也可以修改为其他第二列未出现的值,最终都会被替换成映射关系
Code = [-2,0;-2,1;-2,4;-2,5;-2,12;-2,13;-2,14;-2,30;-2,31];
for i=1:9
drder=1;
for j=1:9
if num_Map_origin_I(i,2) < num_Map_origin_I(j,2)
drder = drder + 1; %排序寻找最小值
end
end
while Code(drder) ~= -2 %防止两种标记类别中像素的个数相等
drder = drder + 1;
end
Code(drder,1) = num_Map_origin_I(i,1); %第一列从小到大排列了出现的标记顺序
end
%% 将Map映射关系用二进制比特流表示
Code_Bin = zeros();
t = 0; %计数
for i=0:8
for j=1:9
if Code(j,1) == i
value = Code(j,2);
end
end
if value == 0
Code_Bin(t+1) = 0;
Code_Bin(t+2) = 0;
t = t+2;
elseif value == 1
Code_Bin(t+1) = 0;
Code_Bin(t+2) = 1;
t = t+2;
else
add = ceil(log2(value+1)); %表示标记编码的长度
Code_Bin(t+1:t+add) = dec2bin(value)-'0'; %将value转换成二进制数组
t = t + add;
end
end
end
哈夫曼解码:
function [value,this_end] = Huffman_DeCode(Binary,last_end)
% 求二进制比特流Binary中下一个Huffman编码转换成的整数值
% 输入:Binary(二进制映射序列),last_end(上一个映射结束的位置)
% 输出:value(十进制整数值)→{0,1,4,5,12,13,14,30,31},end(本次结束的位置)
len = length(Binary);
i = last_end+1;
t = 0; %计数
if i <= len
if i+1<=len && Binary(i)==0 %→0
t = t + 1;
if Binary(i+1) == 0 %→00表示0
t = t + 1;
value = 0;
elseif Binary(i+1) == 1 %→01表示1
t = t + 1;
value = 1;
end
else % Binary(i)==1
if i+2<=len && Binary(i+1)==0 %→10
t = t + 2;
if Binary(i+2) == 0 %→100表示4
t = t + 1;
value = 4;
elseif Binary(i+2) == 1 %→101表示5
t = t + 1;
value = 5;
end
else % Binary(i+1)==1
if i+3<=len && Binary(i+2)==0 %→110
t = t + 3;
if Binary(i+3) == 0 %→1100表示12
t = t + 1;
value = 12;
elseif Binary(i+3) == 1 %→1101表示13
t = t + 1;
value = 13;
end
else % Binary(i+2)==1
if i+3 <= len
t = t + 3;
if Binary(i+3) == 0 %→1110表示14
t = t + 1;
value = 14;
elseif i+4<=len && Binary(i+3)==1 %→1111
t = t + 1;
if Binary(i+4) == 0 %→11110表示30
t = t + 1;
value &#