Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

The difference between PDWT and Matlab's DWT2 function. #7

Open
zhongxiangrong opened this issue Dec 6, 2023 · 4 comments
Open

The difference between PDWT and Matlab's DWT2 function. #7

zhongxiangrong opened this issue Dec 6, 2023 · 4 comments

Comments

@zhongxiangrong
Copy link

I tried to reproduce the 2D discrete wavelet transform in Matlab and PDWT, and then plotted a histogram of the cA parameter. The results are shown in the figure below, with red representing the result from Matlab and blue representing the result from PDWT. I would like to know what could be the possible reasons for this situation?
hist
This is my C++ code.
Wavelets w(img_f,rows,cols,"haar",1,1,1,0,0,2); w.forward(); w.get_coeff(LL, 0); //....change LL(float *) to LL(cv::Mat) cv::Mat hist_cA; const int bin = 256; float range[] = {0,255}; const float* histRange[] = {range}; cv::normalize(LL,LL,0,255,cv::NORM_MINMAX,-1); cv::calcHist(&LL,1,0,cv::Mat(),hist_cA,1,&bin,histRange,true);

This is the Matlab code.
[LL,LH,HL,HH] = dwt2(I1,'haar'); hist_cA = imhist(mat2gray(LL));

@pierrepaleo
Copy link
Owner

pierrepaleo commented Dec 6, 2023

Hi @zhongxiangrong

If I remember correctly Matlab uses a different extension mode by default. PDWT always uses the periodic extension mode. Probably that's the cause of the discrepancy.

I just tried with

C = imread('ngc6543a.jpg');
I1 = C(:, :, 1);
imwrite(I1, "ngc6543a_gray.tif")
[LL,LH,HL,HH] = dwt2(I1,'haar', 'mode', 'ppd');
save("LL.mat", LL)

and on the other hand with the python wrapper to PDWT:

from tifffile import imread
from pycudwt import Wavelets
from scipy.io import loadmat
test_img = imread("ngc6543a_gray.tif")
W = Wavelets(test_img, "haar", 1)
W.forward()

LL = loadmat("LL.mat")["LL"] # result from matlab
print(np.max(np.abs(W.coeffs[0] - LL))) # 1e-13

which gives exactly the same result for the approximation coefficient.

@zhongxiangrong
Copy link
Author

Hi! @pierrepaleo
Thank you very much for your answer. I later found out that the image was subjected to logarithmic operations in the MATLAB code, but not in my C++ code. Referring to your code, I saved the calculated LL component as a tif image in C++, and then used MATLAB to read the LL.tif file. After subtracting it, I found that the maximum error was 5.2871e-08. The wavelet coefficients of PDWT are similar to those of Matlab's wavelet transform.As for the histogram statistics after normalizing the LL, the results are as follows. In fact, the difference in histograms is due to the difference between MATLAB's imhist function and OpenCV's calchist function.
hist2

@zhongxiangrong
Copy link
Author

I have one more question. I have multiple GPUs. Can PDWT choose which specific GPU to perform cuda computation on? In addition, what do the memisonhost, do_separable, and do_cycle_spinning parameters in the Wavelets constructor represent? I look forward to your reply.

@pierrepaleo
Copy link
Owner

IIRC there is no explicit GPU choice parameter in the Wavelets() class. Normally Cuda will automatically pick the "best" GPU at run-time. A way to manually pick a device is via the environment variable CUDA_VISIBLE_DEVICES, though admittedly not ideal.

As for parameters:

  • memisonhost indicates whether the image is on CPU memory rather than on device memory. If memisonhost=1, a host-to-device copy (cudaMemcpyHostToDevice) will be done.
  • do_separable indicates that the transform is separable, i.e that it can be performed as two 1D transforms rather than one 2D transform (same concept as convolution). The Discrete Wavelets Transform commonly found in the literature is separable and implemented as a filter bank. In the 2D case, LL means "low-low" (low-pass filtering on rows, low-pass filtering on columns), LH leans "low-high" (low-pass filtering on rows, high-pass filtering on columns), and so on. In practice this parameter is 1, unless you know what you are doing.
  • do_cycle_spinning is an advanced parameter indicating that a random circular-shift of the image is done before each transform. It serves only for iterative algorithms to reduce thresholding artefacts. It should be set to 0 unless you know what you are doing. Another way to avoid thresholding artefacts is the usage of stationary wavelets transform (undecimated transform) with do_swt=1. There is a whole literature on the subject which I can't cover here.

Hope this helps!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants