FFTW wrong backward transform on 2D image [with Qt] - c++

I created an application in Qt, which allow me to open image and use 2D FFT transform with FFTW library. The problem is that I can not retrieve proper pixel values with backward transformation. But let's start from begining.
This is how looks my FFTW function which I use
void FFTInterface::FFTW(int rows, int cols, QColor **imageInput,fftw_complex * in, fftw_complex * out)
{
fftw_plan g;
g = fftw_plan_dft_2d(rows, cols, in, out, FFTW_FORWARD, FFTW_MEASURE);
int k = 0;
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
in[k][0] = imageInput[i][j].red();
in[k][1] = 0.0;
k++;
}
}
fftw_execute(g);
fftw_destroy_plan(g);
}
rows, cols are size of an image, imageInput is the array of QColor, which keep the pixels value (in greyscale), in and out are object of fftw_complex, input and output arrays.
This function give me some result, which has to be show. To do this, I made some kind of scalling. Firstly, I use abs() function on every value, to be sure that it has positive value. After that, I scale the result.
void FFTInterface::Abs(fftw_complex *out, int rows, int cols)
{
int k = 0;
for(int i = 0; i < rows; i++){
for(int j = 0; j<cols; j++){
out[k][0] = abs(out[k][0]);
out[k][1] = abs(out[k][1]);
k++;
}
}
}
void FFTInterface::Scale(fftw_complex * in,int rows, int cols)
{
float c = 255.0 / log(1+Max(in,rows,cols));
int k = 0;
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
in[k][0] = c*log(1+in[k][0]);
in[k][1] = c*log(1+in[k][0]);
k++;
}
}
}
This process give me something that I need. Image looks ok. But I have problem to revert image to it's original.
Function for BACKWARD is like below
void FFTInterface::IFFTW(int rows, int cols, fftw_complex * in, fftw_complex * out)
{
fftw_plan g;
g = fftw_plan_dft_2d(rows, cols, in, out, FFTW_BACKWARD, FFTW_MEASURE);
int k = 0;
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
in[k][1] = 0.0;
k++;
}
}
fftw_execute(g);
fftw_destroy_plan(g);
}
I found somewhere that it's not normalized (the results are VERY BIG). To normalize I just divide values by N (256,512 etc.) - width or height of the image (it's always a square), but the values are different then the original ones.
Do you have any idea where I'm missing something? Scalling? I should maybe use other fft method from library? I have stucked.

By taking the absolute value and scaling the complex components for the purpose of displaying the image you are modifying the data in such a way that the inverse transform no longer gives you the original input. To avoid this problem I would suggest you create a copy of the data you wish to display before you scale it. Also, make sure not to forget that the input to the inverse transform should be the output from the forward transform (or the last output in a signal processing chain as may be).
In pseudo-code you could do this like so:
interface.FFTW(rows, cols, imageInput, in, out);
size_t N = rows*cols;
fftw_complex* todisplay = fftw_malloc(N);
std::copy(out, out+N, todisplay);
interface.Abs(todisplay);
interface.Scale(todisplay);
... display "todisplay" on your Qt user interface
fftw_free(todislay);
interface.IFFTW(rows, cols, out, reconstructed);

Related

how to use open dft in 2d vector

I would like to ask how to use the dft function in opencv to do Fourier transform with 2d vector.
I have error in my code ...
thank you all
//2d vector in here v1 and v2
//vector size is 1000*1000
//i have to do about 600 images in this process
for (int k = 0; k < 600; k++){
vector <vector <complex < double >>> v1(InputWidth, vector<complex < double >>(InputHeight));
vector <vector <complex < double >>> v2(InputWidth, vector<complex < double >>(InputHeight));
for (int i = 0; i < InputWidth; i++) {
int tempIndex = i*InputHeight;
for (int j = 0; j < InputHeight; j++)
{
int Correction_value = ProjectionImage[k]->data.s[tempIndex + j] * meshGrid[tempIndex + j];
ProjectionImage[k]->data.s[tempIndex + j] = Correction_value;
//v1 is an image
v1[i][j] = Correction_value;
}
}
//error happen in here
dft(v1, v2, DFT_COMPLEX_OUTPUT);
//do frequency filter
for (int i = 0; i < InputWidth; i++) {
for (int j = 0; j < InputHeight; j++)
{
v2[i][j] *= filter_2D[i][j];
}
}
//inverse fourier transform
idft(v2, v1, DFT_COMPLEX_OUTPUT);
}
error message
What is happening here is that you create a std::vector of pointers to other vectors. Those other vectors contain the pixel data. But those data are therefore not necessarily contiguous. Each row (or column) of your image is stored in its own memory segment. OpenCV expects all pixels to be in the same memory segment.
In short, simply copy your pixel data to a form supported by OpenCV, such as a cv::Mat.

C++: Reshape vector to 3D array

Edit: I have uploaded the vector to Drive as a text file, in case anyone want to have a look: https://drive.google.com/file/d/0B0wsPU8YebRQbDUwNFYza3ljSnc/view?usp=sharing
I'm trying to reshape my vector h into a 3D array. h contains 295788 elements. In this case height = 314, width = 314 and depth = 3.
Basically what I'm trying to do is what MATLAB does with its reshape function.
h = reshape(h, height, width, depth)
This is my attempt so far, but when I print it all I see is zeroes, which is not right. I have double checked that h contains the numbers I'm expecting.
vector<vector<vector<double> > > array3D;
int height = 314, width = 314, depth = 3;
// Set up sizes
array3D.resize(height);
for (int i = 0; i < height; ++i) {
array3D[i].resize(width);
for (int j = 0; j < width; ++j)
array3D[i][j].resize(depth);
}
for (int i = 0; i < height; i++)
{
array3D[i][0][0] = h[i];
for (int j = 0; j < width; j++)
{
array3D[i][j][0] = h[i+j];
for (int k = 0; k < depth; k++)
{
array3D[i][j][k] = h[i+j+k];
}
}
}
Printing:
for (vector<vector<vector<double>>>::const_iterator i = array3D.begin(); i != array3D.end(); ++i)
{
for (vector<vector<double>>::const_iterator j = i->begin(); j != i->end(); ++j)
{
for (vector<double>::const_iterator k = j->begin(); k != j->end(); ++k)
{
cout << *k << ' ';
}
}
}
So my question is, how do I convert my vector into a 3D array properly?
I managed to do this by using Eigen::Tensor as suggested by Henri Menke. I ended up creating an array for the initial 314x314x3 matrix, and then another one for the 300x300x3 matrix. It's neither fast nor pretty, but for now that is what I could come up with. Looks like this.
For clarification: margin is calculated further up in the code, but in this example with the 314x314x3 matrix it's margin=7. h is a vector with 295788 elements. nrh=314, nch=314 and nradii=3.
Tensor<int, 3> t(nrh, nch, nradii);
int counter = 0;
for (int k = 0; k < nradii; k++)
{
for (int col = 0; col < nch; col++)
{
for (int row = 0; row < nrh; row++)
{
t(row, col, k) = h[counter];
counter += 1;
}
}
}
int height = nrh - margin * 2;
int width = nch - margin * 2;
int depth = nradii;
Tensor<int, 3> out(height, width, depth);
int count1 = 0, count2 = 0, count3 = 0;
for (int k = 0; k < depth; k++)
{
for (int j = margin; j < nch - margin; j++)
{
for (int i = margin; i < nrh - margin; i++)
{
out(count1, count2, count3) = t(i, j, k);
count1 += 1;
}
count1 = 0;
count2 += 1;
}
count2 = 0;
count3 += 1;
}
Edit: Solution #2 with Tensor.slice()
int height = nrh - margin * 2;
int width = nch - margin * 2;
int depth = nradii;
Tensor<int, 3> tensor(height, width, depth);
DSizes<ptrdiff_t, 3> indices(margin, margin, 0);
DSizes<ptrdiff_t, 3> sizes(height, width, nradii);
tensor = t.slice(indices, sizes);
How about:
array3D[i][j][k] = h[i*(depth*width)+j*depth+k];
That may or may not be scanning the vector in the correct order.
Notice how when the index k resets the index j increments so you move on exactly one until the index j resets in which case i increments and the same. It's easy to show this calculation reads every element exactly once.
I'd normally expect a width, height then depth and you're scanning in the opposite order!
Footnote: Depending on the application is may be worthwhile to just access the vector using this approach. In general it turns out to be faster than accessing a vector of vectors of vectors. That can be relevant when dealing with massive arrays.
Actually, your the structure of your code is already ok, however, there are two mistakes:
The lines
array3D[i][0][0] = h[i];
and
array3D[i][j][0] = h[i+j];
are pointless. You are overwriting those entries later on with the line
array3D[i][j][k] = h[i+j+k];
The index calculation for h[] is wrong: You must multiply the row index by the length of a row before adding the cell index. The assignment should look like this:
array3D[i][j][k] = h[(i*width+j)*depth+k];
Otherwise, you will get the same result for (i, j, k) == (3, 2, 1) as for (i, j, k) == (1, 3, 2), which is obviously wrong. In the index calculation above, I have assumed that k is the fastest changing dimension. If that is not the order in which your data is stored in h, you need to change the positions of i, j, and k and adjust the factors accordingly.
Putting this together, your assignment loop should read:
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
for (int k = 0; k < depth; k++) {
array3D[i][j][k] = h[(i*width+j)*depth+k];
}
}
}
Slightly off-topic:
If you were using C instead of C++, you could "simply" do this:
size_t dataSize;
//Create a real 3D array with the dimensions (height, width, depth).
double (*array3D)[width][depth] = malloc(dataSize = height*sizeof(*array3D));
//Copy over the data from the file.
memcpy(array3D, h, dataSize);
//Print the array contents:
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
for (int k = 0; k < depth; k++) {
printf("%d ", array3D[i][j][k]);
}
}
}
This uses a real 3D array instead of an array of pointers to arrays of pointers to arrays of doubles (which is roughly what a vector<vector<vector<double>>> is). However, this cannot be done in C++ as C++ does not allow for array types with dynamic sizes as C does.

Multiplying Matrices using 2d Vectors in C++

I'm trying to design a program that creates a matrix using vectors of vectors of integers, and then multiplyies it with another matrix. I know how to multiply matrices on paper, but when I try to implement it in my program, I'm not getting it to work. I know that both matrices are entered correctly and are passed correctly as I have the the output of those functions so that I can debug. The program works incorrectly when I try to multiply them. The answer and the number of elements are not right. I know I'm missing something but can't figure out what.
Matrix Matrix::operator*(Matrix m){
vector<int> mRow = m.getRow(0);
vector<int> mCol = m.getCol(0);
vector<int> newElem;
int product = 0;
//adds the contents of the 2nd matrix to the 2d vector
vector< vector<int> > m2(mRow.size(), vector<int>(mCol.size()));
for (int i = 0; i < mRow.size(); i++){
mRow.clear();
mRow = m.getRow(i);
for (int j = 0; j < mCol.size(); j++){
m2[j][i] = mRow[j];
}
}
//Multiplies the matrices using the 2d matrix**THIS IS WHERE IT GOES WRONG**
for (int i = 0; i < row; i++){
for (int j = 0; j < column; j++){
product += matrix[i][j]*m2[j][i];
}
newElem.insert(newElem.begin()+i,product);
product = 0;
}
//displays the products so that i can see if its working
for (int i = 0; i < newElem.size(); i++){
cout << " "<<newElem[i]<<endl;
}
//adds the new product vector to a new Matrix object and returns it
Matrix newM(row, mCol.size());
vector<int> temp;
for (int i = 0; i < row; i++){
for (int j = 0; j < mCol.size(); j++){
temp.insert(temp.begin()+j, newElem[0]);
newElem.erase(newElem.begin());
}
newM.setRow(temp,i);
temp.clear();
}
return newM;
}
Although I don't know whether this helps, I'm using this site as a reference for multiplying 2 matrices together.
Your matrix representation has nothing to do with your mistake. You need to have more nested iterations. Think of a result matrix and iterate through that to calculate it's every element. In a pseudocode:
for i in result column
for j in result row
res[i, j] = multiply(m1, m2, i, j)
where multiply function is the nested loop, something like this:
multiply(m1, m2, i, j)
{
val = 0;
for k in row
val += m1[i, k] * m2[k, j]
return val
}
Here is an implementation of the outer loops. Mind you, there are no error checking in the code.
vector<vector<int> > ml;
vector<vector<int> > mr;
// fill in ml and mr
...
// result matrix
vector<vector<int> > res;
// allocate the result matrix
res.resize(ml.size());
for( it = res.begin(); it != res.end(); ++it)
it->resize(ml[0].size());
// loop through the result matrix and fill it in
for( int i = 0; i < res.size(); ++i)
for( int j = 0; j < res[0].size(); ++j)
res[i][j] = multiply(ml, mr, i, j);
Leaving a proper implementation of multiply() function to you.

How to accessing data in cv::mat when the image type is not known at deisgn time?

I have a set of input images and one output image and I need to combine the input images and create output image.
I have this code:
for (int j = 0; j < Height; ++j)
{
for (int i = 0; i < Width; ++i)
{
int xx,yy,Id;
algo.calXY(i, j, xx, yy,Id);
cv::Vec3b value=cubeImage.images[Id].at<cv::Vec3b>(yy,xx);
output.at<cv::Vec3b>(j,i)=value;
}
}
This code works only if the input images are RGB without alpha channel.
How can I change it to so if input images are ARGB, it works properly?
I tried to replace cv::Vec3b with cv::Vec<uchar, output.channels>, but it is not compiling as it needs a compile time variable for type.
You can make this work by copying one channel at a time:
for (int j = 0; j < Height; ++j)
{
uchar* orow = output.ptr<uchar>(j);
for (int i = 0; i < Width; ++i)
{
int xx, yy, Id;
algo.calXY(i, j, xx, yy, Id);
//cv::Vec3b value=cubeImage.images[Id].at<cv::Vec3b>(yy,xx);
uchar* mrow = cubeImage.images[Id].ptr<uchar>(yy);
mrow += xx * output.channels();
// output.at<cv::Vec3b>(j,i)=value;
for(int c = 0; c < output.channels(); ++ c)
*orow++ = *mrow++;
}
}

optimize 2D array in C++

I'm dealing with a 2D array with the following characteristics:
const int cols = 500;
const int rows = 100;
int arr[rows][cols];
I access array arr in the following manner to do some work:
for(int k = 0; k < T; ++k) { // for each trainee
myscore[k] = 0;
for(int i = 0; i < cols; ++i) { // for each sample
for(int j = 0; j < rows; ++j) { // for each expert
myscore[k] += delta(i, anotherArray[k][i], arr[j][i]);
}
}
}
So I am worried about the array 'arr' and not the other one. I need to make this more cache-friendly and also boost the speed. I was thinking perhaps transposing the array but I wasn't sure how to do that. My implementation turns out to only work for square matrices. How would I make it work for non-square matrices?
Also, would mapping the 2D array into a 1D array boost the performance? If so, how would I do that? Finally, any other advice on how else I can optimize this... I've run out of ideas, but I know that arr[j][i] is the place where I need to make changes because I'm accessing columns by columns instead of rows by rows so that is not cache friendly at all.
Thanks,
Hristo
A general in-place matrix transposition is very difficult, but if you're okay with transposing it to another array, then it's pretty simple.
const int cols = 500;
const int rows = 100;
int arr[rows][cols];
// fill arr[][]
int arrT[cols][rows];
for (int r = 0; r < rows; r++) {
for (int c = 0; c < cols; c++) {
arrT[c][r] = arr[r][c];
}
}
Of course, depending on how you're getting arr[][], you can just fill arrT[][] directly instead.
However, there may be a simpler solution of simple swapping the order of the loops.
for(int k = 0; k < T; ++k) { // for each trainee
myscore[k] = 0;
for(int j = 0; j < rows; ++j) { // for each expert
for(int i = 0; i < cols; ++i) { // for each sample
myscore[k] += delta(i, anotherArray[k][i], arr[j][i]);
}
}
}
Yes, 1d should be faster than 2d. C and C++ arrays are always 1d (internally).
When you call something like
array[row][col]
the compiler actually calculates
col + row * maxcols
and uses that as the actual index of a 1d array. You might as well do that yourself. Cycling through an entire array will be way faster, and random access will be equally fast as in a 2d array.
for(int i = 0; i < N; ++i) { // for each sample
for(int j = 0; j < E[i]; ++j) { // for each expert
... arr[j][i] ... // each ++j causes a large stride => poor caching
}
}
transpose the loops:
for(int j = 0; j < E[i]; ++j) { // for each expert
for(int i = 0; i < N; ++i) { // for each sample
... arr[j][i] ... // each ++i looks to the next word in memory => good
}
}
Of course, without seeing everything else in the program, I can't say if that would cause a problem. If delta doesn't have side effects, you should be fine.
You want memory accesses to be adjacent. In your case simply swap I and j when accessing arr.