Search code examples
matlabbit-manipulationsteganographydwt

How to modify the last 3 bits of signed numbers


When I apply the function dwt2() on an image, I get the four subband coefficients. By choosing any of the four subbands, I work with a 2D matrix of signed numbers.

In each value of this matrix I want to embed 3 bits of information, i.e., the numbers 0 to 7 in decimal, in the last 3 least significant bits. However, I don't know how to do that when I deal with negative numbers. How can I modify the coefficients?


Solution

  • First of all, you want to use an Integer Wavelet Transform, so you only have to deal with integers. This will allow you a lossless transformation between the two spaces without having to round float numbers.

    Embedding bits in integers is a straightforward problem for binary operations. Generally, you want to use the pattern

    (number AND mask) OR bits
    

    The bitwise AND operation clears out the desired bits of number, which are specified by mask. For example, if number is an 8-bit number and we want to zero out the last 3 bits, we'll use the mask 11111000. After the desired bits of our number have been cleared, we can substitute them for the bits we want to embed using the bitwise OR operation.

    Next, you need to know how signed numbers are represented in binary. Make sure you read the two's complement section. We can see that if we want to clear out the last 3 bits, we want to use the mask ...11111000, which is always -8. This is regardless of whether we're using 8, 16, 32 or 64 bits to represent our signed numbers. Generally, if you want to clear the last k bits of a signed number, your mask must be -2^k.

    Let's put everything together with a simple example. First, we generate some numbers for our coefficient subband and embedding bitstream. Since the coefficient values can take any value in [-510, 510], we'll use 'int16' for the operations. The bitstream is an array of numbers in the range [0, 7], since that's the range of [000, 111] in decimal.

    >> rng(4)
    >> coeffs = randi(1021, [4 4]) - 511
    
    coeffs =
    
       477   202  -252   371
        48  -290   -67   494
       483   486   285  -343
       219  -504  -309    99
    
    >> bitstream = randi(8, [1 10]) - 1
    
    bitstream =
    
         0     3     0     7     3     7     6     6     1     0
    

    We embed our bitstream by overwriting the necessary coefficients.

    >> coeffs(1:numel(bitstream)) = bitor(bitand(coeffs(1:numel(bitstream)), -8, 'int16'), bitstream, 'int16')
    
    coeffs =
    
       472   203  -255   371
        51  -289   -72   494
       480   486   285  -343
       223  -498  -309    99
    

    We can then extract our bitstream by using the simple mask ...00000111 = 7.

    >> bitand(coeffs(1:numel(bitstream)), 7, 'int16')
    
    ans =
    
         0     3     0     7     3     7     6     6     1     0