I'm working on a research project concerning image watermarking. The main part of it is the actual watermark embedding scheme, which I have chosen to be the robust blind color image watermarking in quaternion Fourier transform domain. I have started the implementation using OpenCV python interface and got stuck on the step where I have to do the quaternion Fourier transform. The description in the article doesn't help a lot. My code is very basic:
img = cv2.imread("jurassic_world.jpg", cv2.IMREAD_COLOR)
here image is being split into 8x8 blocks.
fft = np.fft.fft(img)
return map(lambda row: map(lambda pix:(sum(pix.real), pix[0].imag, pix[1].imag, pix[2].imag), row) , fft)
From the article:
Jiang et al. (2008) introduced the fast algorithms of the 2D quaternion Fourier transform by using the traditional complex fast Fourier transforms, in which each part Fourier transform is calculated by FFT algorithm by means of separating a quaternion into a real part and other imaginary parts. The fast quaternion Fourier transform of color image f(m,n) can be represented as:
F(u,v) = i(Real(Rrft) + μImag(Rrft)) + j(Real(Grft) + μImag(Grft)) + k(Real(Brft) + μ*Imag(Brft))
where Real(x) denotes the real part of complex number x, Imag(x) denotes the imaginary part of complex number x, and Rrft is the real Fourier transform of array R.
Can someone explain what I'm doing wrong, and show me the right way?
Update 1
I have updated the code to compute separate fft for each color channel. Then I sum the real parts and append imagine ones to form a quaternion.
def computeBlockQFFT(block):
fft0 = np.fft.fft(block[:,:,0])
fft1 = np.fft.fft(block[:,:,1])
fft2 = np.fft.fft(block[:,:,2])
res = np.empty([block.shape[0],block.shape[1],block.shape[2]+1])
res[:,:,0] = fft0[:,:].real + fft1[:,:].real + fft2[:,:].real
res[:,:,1] = fft0[:,:].imag
res[:,:,2] = fft1[:,:].imag
res[:,:,3] = fft2[:,:].imag
return res
Now when I plot one color imagine component I get this picture and the data has a form of -764.882831772. The plot looks somewhere similar, however it doesn't match the one from article even though the same Lenna images were used. Can the reason be in the missing μ in my implementation? Also I'm struggling with the inverse transform. There are four components in the inverse formula:
f(u,v) = (Real(Airft) + μImag(Airft)) + i(Real(Cirft) + μImag(Cirft)) + j(Real(Dirft) + μImag(Dirft)) + k(Real(Eirft) + μImag(Eirft))
How can I map them to 3 color channels? Leave out the first one?
np.real
and imaginarynp.imag
parts of the result and add them up. I don't know where the factormu
comes from, but I'm sure that's explained in the article. – roadrunner66F(u,v)
is a quaterion withi
,j
andk
being your imaginary axis. – user9400869