One solution that worked for me is to use the Integer Wavelet Transform, which is also called the lifting scheme . For the Haar wavelet, I saw that it is defined as:
s = floor((A + B) / 2) d = A - B
And for the opposite:
A = s + floor((d + 1) / 2) B = s - floor(d / 2)
All values โโin the whole process are integers. The reason this works is because the formulas contain information about the even and odd parts of pixels / coefficients, so there is no loss of information from rounding. Even if one changes the coefficients and then takes the inverse transform, the recovered pixels will still be integers.
Python implementation example:
import numpy as np def _iwt(array): output = np.zeros_like(array) nx, ny = array.shape x = nx // 2 for j in xrange(ny): output[0:x,j] = (array[0::2,j] + array[1::2,j])//2 output[x:nx,j] = array[0::2,j] - array[1::2,j] return output def _iiwt(array): output = np.zeros_like(array) nx, ny = array.shape x = nx // 2 for j in xrange(ny): output[0::2,j] = array[0:x,j] + (array[x:nx,j] + 1)//2 output[1::2,j] = output[0::2,j] - array[x:nx,j] return output def iwt2(array): return _iwt(_iwt(array.astype(int)).T).T def iiwt2(array): return _iiwt(_iiwt(array.astype(int).T).T)
Some languages โโalready have built-in functions for this purpose. For example, Matlab uses lwt2() and ilwt2() for a two-dimensional wavelet transform of the lift circuit.
els = {'p',[-0.125 0.125],0}; lshaarInt = liftwave('haar','int2int'); lsnewInt = addlift(lshaarInt,els); [cAint,cHint,cVint,cDint] = lwt2(x,lsnewInt) % x is your image xRecInt = ilwt2(cAint,cHint,cVint,cDint,lsnewInt);
An example article where IWT was used for image steganography, Raja, KB et al. (2008) Reliable adaptive image steganography using whole bursts.