1
votes

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?

1
You need to split the image into three color channels and take the FFTs separately. Then the formula shows you to separate the real np.real and imaginary np.imag parts of the result and add them up. I don't know where the factor mu comes from, but I'm sure that's explained in the article.roadrunner66
From this rather accessible article here : ijcsit.com/docs/Volume%205/vol5issue03/ijcsit20140503378.pdf it appears that the use of the (pure) Quaternion in this context is just another convenient way to express a 3 dimensional vector just like complex numbers and 2D vectors share many properties.roadrunner66
@roadrunner66 I have updated the code according to your comment, not taking to account mu, because I've only found that: " μ determines a direction in color space and an obvious choice for color images is the direction corresponding to the luminance axis which connects all the points r=g=b". Not sure what exactly luminance axis would be here...user1691399
@roadrunner66 Do you know, how to transform the quaternion back to an rgb image? Any tips would are welcome =)user1691399
F(u,v) is a quaterion with i,j and k being your imaginary axis.user9400869

1 Answers

0
votes

The formula you quoted:

F(u,v) = i(Real(Rrft) + μImag(Rrft)) + j(Real(Grft) + μImag(Grft)) + k(Real(Brft) + μ*Imag(Brft))

First thing: i,j,k are the imaginary axis. mu is a quaternion and the direction used for the quaternion fourier transform.

When we calculate i*mu, jmuandk*mu, this will give us quaterions again. We map real to 0,ito 1jto 2 andk` to 3.

The formula tells us:

let i*mu*fft0.imag = a0+b0*i+c0*j+d0*k , j*mu*fft1.imag = a1+b1*i+c1*j+d1*k and k*mu*fft2.imag = a2+b2*i+c2*j+d2*k.

res[0] = a0+a1+a2
res[1] = fft0.real + b0+b1+b2
res[2] = fft1.real + c0+c1+c2
res[3] = fft2.real + d0+d1+d2