使用 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

您会注意到提取函数需要消息长度作为参数。这是因为您的嵌入方法在停止提取位时不会以任何方式进行编码。如果您不希望接收者依赖于该参数的知识(他不应该如此),您有几个选择。但是,我会把这个实现留给你,因为它超出了这个问题的范围。

  1. 在嵌入过程中,在您的像素中放置一些转换为消息长度的位,例如前 16 个 bits/wavelet 系数。因此,当提取开始时,它会读取前 16 位,将它们转换为整数,然后继续进行消息提取。
  2. 在您的消息中嵌入一些额外的位,例如 8 个零,这样当您提取秘密时,您知道一旦遇到它们就停止。