Inverse FFT in OpenCV gives different result than Matlab - c++

Using OpenCV, I want to get the same result of Matlab's ifft2 function. In Matlab I get:
A = [1 2 0; 4 5 0; 7 8 9; 10 11 12];
inverse = ifft2(A);
inverse =
5.7500 + 0.0000i -0.1250 + 0.3608i -0.1250 - 0.3608i
-1.7500 - 2.0000i -0.3080 + 0.4665i 0.5580 + 0.0335i
-1.2500 + 0.0000i -0.1250 - 0.2165i -0.1250 + 0.2165i
-1.7500 + 2.0000i 0.5580 - 0.0335i -0.3080 - 0.4665i
In OpenCV, when I do:
cv::Mat paddedA;
int m = cv::getOptimalDFTSize(A.rows);
int n = cv::getOptimalDFTSize(A.cols);
cv::copyMakeBorder(A, paddedA, 0, m - A.rows, 0, n - A.cols, cv::BORDER_CONSTANT, cv::Scalar::all(0));
cv::Mat planes[] = { cv::Mat_<float>(paddedA), cv::Mat::zeros(paddedA.size(), CV_32F) };
cv::Mat complexA;
cv::merge(planes, 2, complexA);
cv::Mat inverse;
cv::idft(complexA, inverse, cv::DFT_SCALE | cv::DFT_COMPLEX_OUTPUT);
This gives me:
inverse = [1, -0, 2, -0, 0, -0;
4, -0, 5, -0, 0, -0;
7, -0, 8, -8, 9, 0;
10, -0, 11, -0, 12, -0]
And the type of A is CV_32F. How can I get the same result as that of Matlab?

You are using two different functions. FFT is optimized version of DFT. You should use step function in matlab then compare the results.

Related

OpenCV col-wise standard deviation result vs MATLAB

I've seen linked questions but I can't understand why MATLAB and OpenCV give different results.
MATLAB Code
>> A = [6 4 23 -3; 9 -10 4 11; 2 8 -5 1]
A =
6 4 23 -3
9 -10 4 11
2 8 -5 1
>> Col_step_1 = std(A, 0, 1)
Col_step_1 =
3.5119 9.4516 14.2945 7.2111
>> Col_final = std(Col_step_1)
Col_final =
4.5081
Using OpenCV and this function:
double getColWiseStd(cv::Mat in)
{
CV_Assert( in.type() == CV_64F );
cv::Mat meanValue, stdValue, m2, std2;
cv::Mat colSTD(1, A.cols, CV_64F);
cv::Mat colMEAN(1, A.cols, CV_64F);
for (int i = 0; i < A.cols; i++)
{
cv::meanStdDev(A.col(i), meanValue, stdValue);
colSTD.at<double>(i) = stdValue.at<double>(0);
colMEAN.at<double>(i) = meanValue.at<double>(0);
}
std::cout<<"\nCOLstd:\n"<<colSTD<<std::endl;
cv::meanStdDev(colSTD, m2, std2);
std::cout<<"\nCOLstd_f:\n"<<std2<<std::endl;
return std2.at<double>(0,0);
}
Applied to the same matrix yields the following:
Matrix:
[6, 4, 23, -3;
9, -10, 4, 11;
2, 8, -5, 1]
COLstd:
[2.867441755680876, 7.71722460186015, 11.67142760000773, 5.887840577551898]
COLstd_f:
[3.187726614989861]
I'm pretty sure that the OpenCV and MATLAB std function are correct, and thus can't find what I'm doing wrong, am I missing a type conversion? Something else?
The standard deviation you're calculating in OpenCV is normalised by number of observations (N) whereas you're calculating standard deviation in MATLAB normalised by N-1 (which is also the default normalisation factor in MATLAB and is known as Bessel's correction). Hence there is the difference.
You can normalise by N in MATLAB by selecting the second input argument as 1:
Col_step_1 = std(A, 1, 1);
Col_final = std(Col_step_1, 1);

Improper Translation Matrix from SVD of Essential Matrix for 3D reconstruction using 2 Images

I am trying to find a 3D model from 2 images taken from the same camera using OpenCV with C++. I followed this method. I am still not able to rectify mistake in R and T computation.
Image 1: With Background Removed for eliminating mismatches
Image 2: Translated only in X direction wrt Image 1 With Background Removed for eliminating mismatches
I have found the Intrinsic Camera Matrix (K) using MATLAB Toolbox. I found it to be :
K=
[3058.8 0 -500
0 3057.3 488
0 0 1]
All image matching keypoints (using SIFT and BruteForce Matching, Mismatches Eliminated) were aligned wrt center of image as follows:
obj_points.push_back(Point2f(keypoints1[symMatches[i].queryIdx].pt.x - image1.cols / 2, -1 * (keypoints1[symMatches[i].queryIdx].pt.y - image1.rows / 2)));
scene_points.push_back(Point2f(keypoints2[symMatches[i].trainIdx].pt.x - image1.cols / 2, -1 * (keypoints2[symMatches[i].trainIdx].pt.y - image1.rows / 2)));
From Point Correspondeces, I found out Fundamental Matrix Using RANSAC in OpenCV
Fundamental Matrix:
[0 0 -0.0014
0 0 0.0028
0.00149 -0.00572 1 ]
Essential Matrix obtained using:
E = (camera_Intrinsic.t())*f*camera_Intrinsic;
E obtained:
[ 0.0094 36.290 1.507
-37.2245 -0.6073 14.71
-1.3578 -23.545 -0.442]
SVD of E:
E.convertTo(E, CV_32F);
Mat W = (Mat_<float>(3, 3) << 0, -1, 0, 1, 0, 0, 0, 0, 1);
Mat Z = (Mat_<float>(3, 3) << 0, 1, 0, -1, 0, 0, 0, 0, 0);
SVD decomp = SVD(E);
Mat U = decomp.u;
Mat Lambda = decomp.w;
Mat Vt = decomp.vt;
New Essential Matrix for epipolar constraint:
Mat diag = (Mat_<float>(3, 3) << 1, 0, 0, 0, 1, 0, 0, 0, 0);
Mat new_E = U*diag*Vt;
SVD new_decomp = SVD(new_E);
Mat new_U = new_decomp.u;
Mat new_Lambda = new_decomp.w;
Mat new_Vt = new_decomp.vt;
Rotation from SVD:
Mat R1 = new_U*W*new_Vt;
Mat R2 = new_U*W.t()*new_Vt;
Translation from SVD:
Mat T1 = (Mat_<float>(3, 1) << new_U.at<float>(0, 2), new_U.at<float>(1, 2), new_U.at<float>(2, 2));
Mat T2 = -1 * T1;
I was getting the R matrices to be :
R1:
[ -0.58 -0.042 0.813
-0.020 -0.9975 -0.066
0.81 -0.054 0.578]
R2:
[ 0.98 0.0002 0.81
-0.02 -0.99 -0.066
0.81 -0.054 0.57 ]
Translation Matrices:
T1:
[0.543
-0.030
0.838]
T2:
[-0.543
0.03
-0.83]
Please clarify wherever there is a mistake.
This 4 sets of P2 matrix R|T with P1=[I] are giving incorrect triangulated models.
Also, I think the T matrix obtained is incorrect, as it was supposed to be only x shift and no z shift.
When tried with same image1=image2 -> I got T=[0,0,1]. What is the meaning of Tz=1? (where there is no z shift as both images are same)
And should I be aligning my keypoint coordinates with image center, or with principle focus obtained from calibration?

Equivalent function of Matlab's filter2 in OpenCV

I need to convert the following matlab code into OpenCV and obtain exactly the same result.
In matlab:
A = [1 2 3];
f = [4 5 6];
result = filter2(f, A);
This gives out as:
result = [17 32 23]
In OpenCV, I tried these lines:
cv::Mat A = (cv::Mat_<float>(1, 3) << 1, 2, 3);
cv::Mat f = (cv::Mat_<float>(1, 3) << 4, 5, 6);
cv::Mat result;
cv::filter2D(A, result, -1, f, cv::Point(-1, -1), 0, cv::BORDER_REPLICATE);
This gives me:
result = [21 32 41]
How can I obtain the same result as of Matlab?? I doubt the anchor point in OpenCV causes this difference, but I cannot figure out how to change it. Thanks in advance.
Use cv::BORDER_CONSTANT, which pads the array with zero rather than duplicating the neighboring element:
cv::filter2D(A, result, -1, f, cv::Point(-1, -1), 0, cv::BORDER_CONSTANT);
Result is:
result = [17, 32, 23]

OpenCV Mat::ones function

According to the docs, this function should return a Mat with all elements as ones.
Mat m = Mat::ones(2, 2, CV_8UC3);
I was expecting to get a 2x2 matrix of [1,1,1]. Instead, I got this:
[1, 0, 0] [1, 0, 0]
[1, 0, 0] [1, 0, 0]
Is this the expected behaviour?
It looks like Mat::ones() works as expected only for single channel arrays. For matrices with multiple channels ones() sets only the first channel to ones while the remaining channels are set to zeros.
Use the following constructor instead:
Mat m = Mat(2, 2, CV_8UC3, Scalar(1,1,1));
std::cout << m;
Edit. Calling
Mat m = Mat::ones(2, 2, CV_8UC3);
is the same as calling
Mat m = Mat(2, 2, CV_8UC3, 1); // OpenCV replaces `1` with `Scalar(1,0,0)`

calculate gradient directions

I want calculate angles of gradients from depth map and group it for some directions (8 sectors)
But my function calculates only first 3 directions
cv::Mat calcAngles(cv::Mat dimg)//dimg is depth map
{
const int directions_num = 8;//number of directions
const int degree_grade = 360;
int range_coeff = 255 / (directions_num + 1);//just for visualize
cv::Mat x_edge, y_edge, full_edge, angles;
dimg.copyTo(x_edge);
dimg.copyTo(y_edge);
dimg.copyTo(full_edge);
//compute gradients
Sobel( dimg, x_edge, CV_8U, 1, 0, 5, 1, 19, 4 );
Sobel( dimg, y_edge, CV_8U, 0, 1, 5, 1, 19, 4 );
Sobel( dimg, full_edge, CV_8U, 1, 1, 5, 1, 19, 4 );
float freq[directions_num + 1];//for collect direction's frequency
memset(freq, 0, sizeof(freq));
angles = cv::Mat::zeros(dimg.rows, dimg.cols, CV_8U);//store directions here
for(int i = 0; i < angles.rows; i++)
{
for(int j = 0; j < angles.cols; j++)
{
angles.at<uchar>(i, j) = (((int)cv::fastAtan2(y_edge.at<uchar>(i, j), x_edge.at<uchar>(i, j))) / (degree_grade/directions_num) + 1
) * (dimg.at<uchar>(i, j) ? 1 : 0);//fastatan returns values from 0 to 360, if i not mistaken. I want group angles by directions_num sectors. I use first 'direction' (zero value) for zero values from depth map (zero value at my depth map suggest that it is bad pixel)
freq[angles.at<uchar>(i, j)] += 1;
}
}
for(int i = 0; i < directions_num + 1; i++)
{
printf("%2.2f\t", freq[i]);
}
printf("\n");
angles *= range_coeff;//for visualization
return angles;
}
Out from one of the frames:
47359.00 15018.00 8199.00 6224.00 0.00 0.00 0.00 0.00 0.00
(first value is "zero pixel", next is number of gradients in n-place but only 3 are not zero)
Visualization
Is there way out? Or these result is OK?
PS Sorry for my writing mistakes. English in not my native language.
You used CV_8U type for Sobel output. It is unsigned integer 8 bit. So it can store only positive values. That's why fastAtan2 returns less or equal than 90. Change type to CV_16S and use short type for accessing the elements:
cv::Sobel(dimg, x_edge, CV_16S, 1, 0, 5, 1, 19, 4);
cv::Sobel(dimg, y_edge, CV_16S, 0, 1, 5, 1, 19, 4);
cv::fastAtan2(y_edge.at<short>(i, j), x_edge.at<short>(i, j))