Link to home
Start Free TrialLog in
Avatar of @1708
@1708

asked on

DCT of 2D array using fftw in c++

I want to find dct of a matrix in c++ just like how it is done in matlab.
Below is the code I used
#include <fftw3.h>
using namespace std;
 double** create2DArray(int row, int col)
{
	 double** arr = new  double*[row];
	for(int i = 0; i < row; i++)
		arr[i] = new  double[col];
	return arr;
}

int main()
{
int m = 3; 
int n = 3;
 	
      /*double a[m][n] =
   	 {
        {0.2, 0.3 ,1},
        {0 ,12 ,5},
        {0.3, 0.3, 1}
   	 };*/

   double** a= create2DArray(m,n); 
   for( int j = 0; j < m;j++ ) 
  	{	
  		for(int i = 0; i < n; i++)
	   		{	
    						a[i][j] = Signal[i]*hamming[i];
			}
  	 }

   double** b= create2DArray(m,n);   
   
    printf("Original vector\n");
	for(int i=0;i<m;i++)
	 {    
	  for(int j = 0 ;j<n;j++)
	     {
	        cout << a[i][j] <<"  " ;
	     }
	cout<< endl;
	}
  
    

    fftw_plan plan = fftw_plan_r2r_2d(n, m,&a[0][0],&b[0][0], FFTW_REDFT10, FFTW_REDFT10, FFTW_ESTIMATE);
    fftw_execute(plan);
      
    printf("DCT\n");
    for(int i=0;i<m;i++)
	{    
	for(int j = 0 ;j<n;j++)
		{
	cout << b[i][j] <<"  " ;
		}
	cout<< endl;
	}

    
    fftw_plan plani = fftw_plan_r2r_2d(n, m,&b[0][0],&a[0][0], FFTW_REDFT01,  FFTW_REDFT01,FFTW_MEASURE);
     fftw_execute(plani);
    
    printf("IDCT\n");

    
   	for(int i=0;i<m;i++)
	{    
	for(int j = 0 ;j<n;j++)
		{
	cout << a[i][j]/(m*n*4) <<"  " ;
		}
	cout<< endl;
	}
   
  
    return 0;
    

Open in new window


1) Matrix a[m][n] is obtained by multiplying signal with hamming window .
2) When I pass Matrix "a" as input to     " fftw_plan plan = fftw_plan_r2r_2d(n, m,&a[0][0],&b[0][0], FFTW_REDFT10, FFTW_REDFT10, FFTW_ESTIMATE); "
I get the following error :
 cannot convert ‘long double*’ to ‘double*’ for argument ‘4’ to ‘fftw_plan_s* fftw_plan_r2r_2d(int, int, double*, double*, fftw_r2r_kind, fftw_r2r_kind, unsigned int)’

How do I pass a matrix  to DCT function using fftw3 ,which is declared as mentioned above .
PS :When I declared it as double a[m][n] = {//Enter the elements}; //when m =640 ; n = 645
It gives Segmentation fault
{Because of which I tried to define matrix a in heap as mentioned but when given to the dct function throws error .}

Can anyone kindly solve my issue .
Thanks in Advance.
Avatar of phoffric
phoffric

The problem you are having trouble with looks like a similar type of problem as in your other question:  "How to pass a matrix to a function without knowing its size".
https://www.experts-exchange.com/questions/28997412/How-to-pass-a-matrix-to-a-function-without-knowing-its-size.html

If you continue your discussion in your first question to the point of resolving that issue, I think that will help you with this problem.

Could you come up with a simpler complete program (i.e., a few lines of code) that illustrates your problem without bringing in the DCT and Matlab concepts. To illustrate your compiler error and your program crash, you should be able to throw away a good amount of the details in your OP and just deal with the essential issues. Leaving out the DCT and Matlab concepts will help us focus on your C++ problems.
fftw_plan_r2r_2d(int, int, double*, double*, fftw_r2r_kind, fftw_r2r_kind, unsigned int)’
the code you posted uses double arrays. it can't be responsible for the error message which complains that a 'long double *' was passed to function fftw_plan_r2r_2d.

you still are posting code which doesn't fit to your problem what actually makes it impossible to help.

Sara
Avatar of @1708

ASKER

@sarabande
Apologise for the mistake I made ,I got confused :
double** create2DArray(int row, int col)
{
	double** arr = new  double*[row];
	for(int i = 0; i < row; i++)
		arr[i] = new  double[col];
	return arr;
}

int main()
{
int m = 2; 
int n = 2;
 double** a= create2DArray(m,n); 
  //Intilialising Matrix a 
  int count = 1; 	
  for(int i = 0 ; i<m;i++)
   {
     for(int j = 0 ; j<n;j++)
       {
          a[i][j] = count ;//[1 2 ;3 4]
          count++;
       }
   }
    
    
 double** b= create2DArray(m,n);   // To hold the output
  fftw_plan plan = fftw_plan_r2r_2d(n, m,&a[0][0],&b[0][0], FFTW_REDFT10, FFTW_REDFT10, FFTW_ESTIMATE);
 fftw_execute(plan);
      
  fftw_plan plani = fftw_plan_r2r_2d(n, m,&b[0][0],&a[0][0], FFTW_REDFT01,  FFTW_REDFT01,FFTW_MEASURE);
  fftw_execute(plani);
  return 0;
  
}

Open in new window


The following code :output the following result :
Original matrix
1  2  
3  4  
DCT
12  -2.82843  
0  0  
IDCT
16  32  
3  4

1) IDCT is found (and is correct ) only for the first row .
2) DCT output is wrong .

The correct output should have been :
DCT
40  -5.65685  
-11.3137  0  
IDCT
16  32  
48  64
please post the code of function fftw_plan_r2r_2d and corresponding matlab code.

i found c sample code using float type (which only has a precison of 5 to 6 significant decimal digits.

so i would assume that using long double type for all would not solve the problem.

did you correctly use zero-based arrays in your c code when porting the matlab code (where all arrays are 1-based) ?

Sara
Avatar of @1708

ASKER

fftw_plan_r2r_2d is not a user defined function .
I have used the library  #include <fftw3.h>  in my code .Which uses  fftw_plan_r2r_2d  to do dct on matrix .
And the result of this dct would be "similiar " to the dct2  in matlab , but different by a scaling factor .
The code workes fine when input matrix is defines as
double a [m][n] = {{1,2},{3,4}};
When when declared as shown in code 2 , ends up in wrong result .
The code workes fine when input matrix is defines as
 double a [m][n] = {{1,2},{3,4}};

ok. then you need to change the create2DArray to create an 1d array (actually it is as if you would concatenate the rows of the matrix).

double* create2DArray(int row, int col)
{
	double* arr = new  double[row*col];
	return arr;
}

int main()
{
   int m = 2; 
   int n = 2;
   double* a= create2DArray(m,n); 
  //Intilialising Matrix a 
  int count = 1; 	
  for(int i = 0 ; i<m;i++)
   {
     for(int j = 0 ; j<n;j++)
       {
          a[i*n+j] = count ;//[1 2 ;3 4]
          count++;
       }
   }
  
    
 double* b= create2DArray(m,n);   // To hold the output
  fftw_plan plan = fftw_plan_r2r_2d(n, m, a, b, FFTW_REDFT10, FFTW_REDFT10, FFTW_ESTIMATE);
 fftw_execute(plan);
      
  fftw_plan plani = fftw_plan_r2r_2d(n, m, b, a, FFTW_REDFT01,  FFTW_REDFT01,FFTW_MEASURE);
  fftw_execute(plani);
  delete[]a;
  delete[]b;
  //delete fftw_plan; // ??
  return 0;
  
}

Open in new window


Sara
ASKER CERTIFIED SOLUTION
Avatar of sarabande
sarabande
Flag of Luxembourg image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of @1708

ASKER

Thanks a lot for your feedback .
the function fftw_plan_r2r_2d expects the matrix to be passed as in the second case.
because of this you also could use a std::vector<double> for your matrix.

std::vector<double> a(m*n);
int count = 1; 	
for(int i = 0 ; i<m;i++)
{
     for(int j = 0 ; j<n;j++)
       {
          a[i*n+j] = count ;//[1 2 ;3 4]
          count++;
       }
 }

std::vector<double> b(m*n);
fftw_plan plan = fftw_plan_r2r_2d(n, m, &a[0], &b[0], FFTW_REDFT10, FFTW_REDFT10, FFTW_ESTIMATE);
...

Open in new window


a std::vector provides a contiguous 1d array (same as the corrected create2DArray). differently, you would not need to care for deletion, as the std::vector has a destructor which does that for you.

Sara