使用 DWT Haar 变换方法将文本隐藏在系数内
Using DWT Haar transform method to hide text inside coefficients
我写了下面的代码,它对图像进行 Haar 变换并在系数的最低有效位中一点一点地嵌入秘密消息。为了使用 bitset 函数,我将双精度系数转换为 uint64,并在嵌入后将它们改回。
function DwtSteg(address,message)
coverImage=imread(address);
ascii=uint8(message);
[LL LH HL HH]=dwt2(coverImage,'haar');
LH=round(LH);
HL=round(HL);
subplot(1,2,1)
imshow(LH)
[r c]=size(LL);
wc=1;
bc=1;
done=false;
for i=1:r
if(done)
break
end
for j=1:c
if(bc==8)
bc=1;
wc=wc+1;
end
if(wc==length(message))
done=true;
break;
end
xb = typecast(LH(i,j), 'uint64' );
xb=bitset(xb,1,bitget(ascii(wc),bc));
xb%***
LH(i,j)=typecast(xb, 'double');
bc=bc+1;
end
end
subplot(1,2,2)
imshow(LH)
stegoImage=idwt2(LL ,HL,LH, HH,'haar');
figure(2)
imshow(uint8(stegoImage));
imwrite(uint8(stegoImage),'stegoImage.tiff');
end
但是当我 运行 下面的代码从 Image.The 中提取我的消息时,系数与转换后的系数不同。(考虑两个函数上的“***”):
function [ str ] = DwtDesteg( address)
str='';
image=imread(address);
[LL LH HL HH]=dwt2(image,'haar');
[r c]=size(LL);
LH=round(LH);
bc=1;
ch=0;
for i=1:r
for j=1:c
if(bc==8)
bc=1;
str=strcat(str,ch);
char(ch)
end
xb = typecast(LH(i,j), 'uint64');
xb%***
ch=bitset(ch,bc,bitget(xb,1));
bitget(xb,1)
bc=bc+1;
end
end
end
由于您将 DWT 系数作为整数进行处理,因此您也可以使用整数变换 IWT。所以,而不是做
[LL LH HL HH]=dwt2(coverImage,'haar');
使用 lwt2()
的提升方案。
% set up a Haar integer lifting scheme
els = {'p',[-0.125 0.125],0};
lshaarInt = liftwave('haar','int2int');
lsnewInt = addlift(lshaarInt,els);
% transform away!
[LL,LH,HL,HH] = lwt2(double(image),lsnewInt);
此时,您不必进行任何舍入,例如 LH = round(LH)
。直接开始嵌入。
imread()
将图像加载为 uint8 类型。当您将其传递给 dwt2()
时,它会将所有内容转换为双精度值。但是,如果您尝试将 uint8 矩阵传递给 lwt2()
,它会报错,因此您必须手动将其转换为 double。对于 inverse transform 只需做
image = ilwt2(LH,LH,HL,HH,lsnewInt);
image = uint8(image);
现在,您的代码还有一些其他错误,例如将 LH
系数类型转换为 uint64
会弄乱位设置。什么都追,有点麻烦,所以重写了你的函数
embed.m
function embed(filein,fileout,message)
image = imread(filein);
message = double(message);
els = {'p',[-0.125 0.125],0};
lshaarInt = liftwave('haar','int2int');
lsnewInt = addlift(lshaarInt,els);
[LL,LH,HL,HH] = lwt2(double(image),lsnewInt);
col = size(LH,2);
r = 1;
c = 1;
for i = 1:length(message);
letter = message(i);
for b = 8:-1:1;
LH(r,c) = bitset(LH(r,c),1,bitget(letter,b));
c = c + 1;
if (c > col)
r = r + 1;
c = 0;
end
end
end
stego = uint8(ilwt2(LL,LH,HL,HH,lsnewInt));
imshow(stego);
imwrite(stego,fileout);
end
extract.m
function extract(filename,messageLength)
image = imread(filename);
els = {'p',[-0.125 0.125],0};
lshaarInt = liftwave('haar','int2int');
lsnewInt = addlift(lshaarInt,els);
[LL,LH,HL,HH] = lwt2(double(image),lsnewInt);
col = size(LH,2);
r = 1;
c = 1;
secret = zeros(messageLength,1);
for i = 1:messageLength;
letter = 0;
for b = 8:-1:1;
letter = bitset(letter,b,bitget(LH(r,c),1));
c = c + 1;
if (c > col)
r = r + 1;
c = 0;
end
end
secret(i) = char(letter);
end
disp(char(secret'));
end
您会注意到提取函数需要消息长度作为参数。这是因为您的嵌入方法在停止提取位时不会以任何方式进行编码。如果您不希望接收者依赖于该参数的知识(他不应该如此),您有几个选择。但是,我会把这个实现留给你,因为它超出了这个问题的范围。
- 在嵌入过程中,在您的像素中放置一些转换为消息长度的位,例如前 16 个 bits/wavelet 系数。因此,当提取开始时,它会读取前 16 位,将它们转换为整数,然后继续进行消息提取。
- 在您的消息中嵌入一些额外的位,例如 8 个零,这样当您提取秘密时,您知道一旦遇到它们就停止。
我写了下面的代码,它对图像进行 Haar 变换并在系数的最低有效位中一点一点地嵌入秘密消息。为了使用 bitset 函数,我将双精度系数转换为 uint64,并在嵌入后将它们改回。
function DwtSteg(address,message)
coverImage=imread(address);
ascii=uint8(message);
[LL LH HL HH]=dwt2(coverImage,'haar');
LH=round(LH);
HL=round(HL);
subplot(1,2,1)
imshow(LH)
[r c]=size(LL);
wc=1;
bc=1;
done=false;
for i=1:r
if(done)
break
end
for j=1:c
if(bc==8)
bc=1;
wc=wc+1;
end
if(wc==length(message))
done=true;
break;
end
xb = typecast(LH(i,j), 'uint64' );
xb=bitset(xb,1,bitget(ascii(wc),bc));
xb%***
LH(i,j)=typecast(xb, 'double');
bc=bc+1;
end
end
subplot(1,2,2)
imshow(LH)
stegoImage=idwt2(LL ,HL,LH, HH,'haar');
figure(2)
imshow(uint8(stegoImage));
imwrite(uint8(stegoImage),'stegoImage.tiff');
end
但是当我 运行 下面的代码从 Image.The 中提取我的消息时,系数与转换后的系数不同。(考虑两个函数上的“***”):
function [ str ] = DwtDesteg( address)
str='';
image=imread(address);
[LL LH HL HH]=dwt2(image,'haar');
[r c]=size(LL);
LH=round(LH);
bc=1;
ch=0;
for i=1:r
for j=1:c
if(bc==8)
bc=1;
str=strcat(str,ch);
char(ch)
end
xb = typecast(LH(i,j), 'uint64');
xb%***
ch=bitset(ch,bc,bitget(xb,1));
bitget(xb,1)
bc=bc+1;
end
end
end
由于您将 DWT 系数作为整数进行处理,因此您也可以使用整数变换 IWT。所以,而不是做
[LL LH HL HH]=dwt2(coverImage,'haar');
使用 lwt2()
的提升方案。
% set up a Haar integer lifting scheme
els = {'p',[-0.125 0.125],0};
lshaarInt = liftwave('haar','int2int');
lsnewInt = addlift(lshaarInt,els);
% transform away!
[LL,LH,HL,HH] = lwt2(double(image),lsnewInt);
此时,您不必进行任何舍入,例如 LH = round(LH)
。直接开始嵌入。
imread()
将图像加载为 uint8 类型。当您将其传递给 dwt2()
时,它会将所有内容转换为双精度值。但是,如果您尝试将 uint8 矩阵传递给 lwt2()
,它会报错,因此您必须手动将其转换为 double。对于 inverse transform 只需做
image = ilwt2(LH,LH,HL,HH,lsnewInt);
image = uint8(image);
现在,您的代码还有一些其他错误,例如将 LH
系数类型转换为 uint64
会弄乱位设置。什么都追,有点麻烦,所以重写了你的函数
embed.m
function embed(filein,fileout,message)
image = imread(filein);
message = double(message);
els = {'p',[-0.125 0.125],0};
lshaarInt = liftwave('haar','int2int');
lsnewInt = addlift(lshaarInt,els);
[LL,LH,HL,HH] = lwt2(double(image),lsnewInt);
col = size(LH,2);
r = 1;
c = 1;
for i = 1:length(message);
letter = message(i);
for b = 8:-1:1;
LH(r,c) = bitset(LH(r,c),1,bitget(letter,b));
c = c + 1;
if (c > col)
r = r + 1;
c = 0;
end
end
end
stego = uint8(ilwt2(LL,LH,HL,HH,lsnewInt));
imshow(stego);
imwrite(stego,fileout);
end
extract.m
function extract(filename,messageLength)
image = imread(filename);
els = {'p',[-0.125 0.125],0};
lshaarInt = liftwave('haar','int2int');
lsnewInt = addlift(lshaarInt,els);
[LL,LH,HL,HH] = lwt2(double(image),lsnewInt);
col = size(LH,2);
r = 1;
c = 1;
secret = zeros(messageLength,1);
for i = 1:messageLength;
letter = 0;
for b = 8:-1:1;
letter = bitset(letter,b,bitget(LH(r,c),1));
c = c + 1;
if (c > col)
r = r + 1;
c = 0;
end
end
secret(i) = char(letter);
end
disp(char(secret'));
end
您会注意到提取函数需要消息长度作为参数。这是因为您的嵌入方法在停止提取位时不会以任何方式进行编码。如果您不希望接收者依赖于该参数的知识(他不应该如此),您有几个选择。但是,我会把这个实现留给你,因为它超出了这个问题的范围。
- 在嵌入过程中,在您的像素中放置一些转换为消息长度的位,例如前 16 个 bits/wavelet 系数。因此,当提取开始时,它会读取前 16 位,将它们转换为整数,然后继续进行消息提取。
- 在您的消息中嵌入一些额外的位,例如 8 个零,这样当您提取秘密时,您知道一旦遇到它们就停止。