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
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.