Cerin
Cerin

Reputation: 64739

Calculate Discrete Cosine Transformation of Image with OpenCV

I'm trying to use the OpenCV 2.3 Python wrapper to calculate the DCT for an image. Supposedly, images == numpy arrays == CV matrices, so I thought this should work:

import cv2
img1 = cv2.imread('myimage.jpg', cv2.CV_LOAD_IMAGE_GRAYSCALE)
img2 = cv2.dct(img1)

However, this throws the error:

cv2.error: /usr/local/lib/OpenCV-2.3.1/modules/core/src/dxt.cpp:2247: error: (-215) type == CV_32FC1 || type == CV_64FC1 in function dct

I realize the error means the input should be either a 32-bit or 64-bit single-channel floating point matrix. However, I thought that's how my image should have loaded when specifying grayscale, or at least it should be close enough so that CV2 should be able to figure out the conversion.

What's the appropriate way to convert an image for DCT using cv2?

Upvotes: 5

Views: 14517

Answers (6)

alyssaeliyah
alyssaeliyah

Reputation: 2244

Heres how to do it with scipy:

import os.path
import numpy as np
from PIL import Image
from scipy.fftpack import fft, dct

if __name__ == '__main__':
    image_counter = 1

    # Apply DCT to the noisy image patches.
    noise_image_path = 'noise_images/' + str(image_counter) + '.png'
    noise_image = Image.open(noise_image_path)         
    noise_dct_data = dct(noise_image)
    print(noise_dct_data)

Upvotes: 0

Nikan Doosti
Nikan Doosti

Reputation: 684

I did not want to write this answer but as I seen some answers are voted up while they are wrong, I decided to write.

The dct operation works on inputs in any range so I really do not understand why others scaled it to [0, 1]. But in opencv, you need to pass numpy.float32 numbers.

x = np.array([8, 16, 24 , 32, 40, 48, 56, 64])
cv2.dct(np.float32(x))

# output
array([[ 101.82337189],
       [ -51.53858566],
       [   0.        ],
       [  -5.38763857],
       [   0.        ],
       [  -1.60722351],
       [   0.        ],
       [  -0.40561762]], dtype=float32)

But if you scale it, almost all small values will be lost.

Here is a link to formula and examples: https://users.cs.cf.ac.uk/Dave.Marshall/Multimedia/node231.html#DCTbasis

Upvotes: 3

Shobhit Puri
Shobhit Puri

Reputation: 26007

Here is a solution that I got from openCV forums and it worked.

img = cv2.imread(fn, 0)      # 1 chan, grayscale!
imf = np.float32(img)/255.0  # float conversion/scale
dst = cv2.dct(imf)           # the dct
img = np.uint8(dst)*255.0    # convert back

Upvotes: 2

Neon22
Neon22

Reputation: 630

Numpy has slice operators for working between arrays of different orders.

import cv2
import cv2.cv as cv
import numpy as np   

img1 = cv2.imread('myimage.jpg')
# or use cv2.CV_LOAD_IMAGE_GRAYSCALE 
img1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)
cv2.imshow('input', img1)
w,h = img1.shape
# make a 32bit float for doing the dct within
img2 = np.zeros((w,h), dtype=np.float32)
print img1.shape, img2.shape
img2 = img2+img1[:w, :h]
dct1 = cv2.dct(img2)
key = -1
while(key < 0):
    cv2.imshow("DCT", dct1)
    key = cv2.waitKey(1)
cv2.destroyAllWindows()

Upvotes: 1

Cerin
Cerin

Reputation: 64739

There doesn't seem to be any easy way to do this with cv2. The closest solution I could find is:

import cv, cv2
import numpy as np

img1 = cv2.imread('myimage.jpg', cv2.CV_LOAD_IMAGE_GRAYSCALE)
h, w = img1.shape[:2]
vis0 = np.zeros((h,w), np.float32)
vis0[:h, :w] = img1
vis1 = cv2.dct(vis0)
img2 = cv.CreateMat(vis1.shape[0], vis1.shape[1], cv.CV_32FC3)
cv.CvtColor(cv.fromarray(vis1), img2, cv.CV_GRAY2BGR)

cv.SaveImage('output.jpg', img2)

Upvotes: 3

mevatron
mevatron

Reputation: 14011

Well, when you load the image as grayscale, it is actually read in at 8-bits per pixel and not as 32-bit float values.

Here is how you would do it:

img1_32f = cv.CreateImage( cv.GetSize(img1), cv.IPL_DEPTH_64F, 1)
cv.Scale(img1, img1_32f, 1.0, 0.0)

Also, have a look at the dft.py example. This should give you a feel for how to use the dft as well.

Upvotes: 1

Related Questions