Reputation: 64739
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
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
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
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
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
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
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