0

I have written the code below which takes the Haar transform of an image and embeds a secret message, bit by bit on in the least significant bits of the coefficients. To use the bitset function I convert the double coefficients to uint64 and I change them back after the embedding.

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

But when I run below code to extract my message from Image.The coefficients aren't same as the converted ones.(consider '***' on both function) :

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
Reti43
  • 9,656
  • 3
  • 28
  • 44
NewUser
  • 87
  • 12
  • @Reti43 No I didn't. How should I do it in this code? – NewUser Mar 24 '16 at 18:06
  • @Reti43 I don't understand where should I put that I know nothing about Integer Wavelet Transform. – NewUser Mar 24 '16 at 18:28
  • @Reti43 Which function I should manipulate : $DwtSteg$ or $DwtDesteg$? Before or after $dwt2$? – NewUser Mar 24 '16 at 18:42
  • @Reti43 It throws these exceptions : `Error using + Integers can only be combined with integers of the same class, or scalar doubles. Error in lsupdate (line 49) y(:,1:last,:) = y(:,1:last,:)+t(:,1:last,:); Error in lwt2 (line 100) case 'd' , H = H + lsupdate('r',L,liftFILT,DF,sH,LStype); Error in DwtSteg (line 12) [LL LH HL HH] = lwt2(coverImage,lsnewInt)` – NewUser Mar 24 '16 at 19:06

1 Answers1

2

Since you're manipulating the DWT coefficients as integers, you may as well work with the integer transform, IWT. So, instead of doing

[LL LH HL HH]=dwt2(coverImage,'haar');

use a lifting scheme with 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);

At this point, you don't have to do any rounding, e.g., LH = round(LH). Just proceed to embedding straight away.

imread() loads the image as a uint8 type. When you pass that to dwt2(), it will convert everything to double. However, if you try to pass a uint8 matrix to lwt2(), it will complain, so you have to manually convert it to double. For the inverse transform simply do

image = ilwt2(LH,LH,HL,HH,lsnewInt);
image = uint8(image);

Now, your code has some other bugs, such as typecasting the LH coefficient to uint64 messes up the bitsetting. It's a bit troubling to chase everything, so I rewrote your functions.

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

You'll notice that the extraction function requires the message length as a parameter. This is because your embedding method does not encode in any way when to stop extracting bits. If you don't want the receiver to be dependent on the knowledge of that parameter, as he shouldn't be, you have a couple of options. However, I'll leave that implementation to you because it's outside the scope of this question.

  1. During embedding put some bits in your pixels that translate to the message length, e.g., the first 16 bits/wavelet coefficients. So when the extraction begins, it reads the first 16 bits, converts them to an integer and then carries on with the message extraction.
  2. Along with your message, embed some extra bits, e.g., 8 zeros, so that when you're extracting the secret, you know to stop once you encounter them.
Reti43
  • 9,656
  • 3
  • 28
  • 44
  • Same issue remained but also Image completely destroyed. `stegoImage = ilwt2(LH,LH,HL,HH,lsnewInt); stegoImage = uint8(stegoImage);` – NewUser Mar 24 '16 at 19:50
  • @NewUser What is the exact problem? Any error messages? *How* is the image destroyed? I've used this exact transform to embed bits in the lsb of coefficients and it has worked just fine. – Reti43 Mar 24 '16 at 19:53
  • take a look at my edit I will remove picture as soon as possible. http://i.stack.imgur.com/rw3Z5.png – NewUser Mar 24 '16 at 20:01
  • @NewUser Your embedding algorithm actually has some bugs. Do you mind if I post a working version, but one that is somewhat different from yours? Just more clearly written. – Reti43 Mar 24 '16 at 20:30
  • thank you... only one step left : `Error using bitset Double inputs must have integer values in the range of ASSUMEDTYPE. Error in embed (line 17) LH(r,c) = bitset(LH(r,c),1,bitget(letter,b));` I used to do typecasting because of this error – NewUser Mar 24 '16 at 20:58
  • @NewUser I swear the code that I posted works for me as is. I'm using version 2013b, so maybe it has changed in a new version. I'm afraid I can't help with this... You can try doing the typecast and see if that works for you. Maybe that's why the typecast messed things up for me. – Reti43 Mar 24 '16 at 21:03
  • @Reti43 How can I use lifting scheme in python. Also, can you point me to some resources to study lifting scheme, not purely mathematical. I am trying to embed data into haar wavelet using http://pywavelets.readthedocs.org/en/latest/ in python. – Himani Agrawal Apr 24 '16 at 03:04