The Image FFT application outputs a spectrum representation of an input image, saving it into spectrum.png. The user can define what backend will be used for processing.
This is using the CUDA backend and one of the provided sample images. You can try with other images, respecting the constraints imposed by the algorithm.
For convenience, here's the code that is also installed in the samples directory.
#include <opencv2/core/version.hpp>
#if CV_MAJOR_VERSION >= 3
# include <opencv2/imgcodecs.hpp>
#else
# include <opencv2/highgui/highgui.hpp>
#endif
#include <cstring>
#include <iostream>
#define CHECK_STATUS(STMT) \
do \
{ \
VPIStatus status = (STMT); \
if (status != VPI_SUCCESS) \
{ \
throw std::runtime_error(vpiStatusGetName(status)); \
} \
} while (0);
cv::Mat LogMagnitude(cv::Mat cpx);
cv::Mat CompleteFullHermitian(cv::Mat in, cv::Size fullSize);
cv::Mat InplaceFFTShift(cv::Mat mag);
int main(int argc, char *argv[])
{
int retval = 0;
try
{
if (argc != 3)
{
throw std::runtime_error(std::string("Usage: ") + argv[0] + " <cpu|pva|cuda> <input image>");
}
std::string strDevType = argv[1];
std::string strInputFileName = argv[2];
cv::Mat cvImage = cv::imread(strInputFileName, cv::IMREAD_GRAYSCALE);
if (cvImage.empty())
{
throw std::runtime_error("Can't open '" + strInputFileName + "'");
}
assert(cvImage.type() == CV_8UC1);
if (strDevType == "cpu")
{
}
else if (strDevType == "cuda")
{
}
else if (strDevType == "pva")
{
}
else
{
throw std::runtime_error("Backend '" + strDevType +
"' not recognized, it must be either cpu, cuda or pva.");
}
{
memset(&imgData, 0, sizeof(imgData));
}
CHECK_STATUS(
{
cv::Mat mag = InplaceFFTShift(LogMagnitude(CompleteFullHermitian(cvSpectrum, cvImage.size())));
normalize(mag, mag, 0, 255, cv::NORM_MINMAX);
imwrite("spectrum_" + strDevType + ".png", mag);
}
}
catch (std::exception &e)
{
std::cerr << e.what() << std::endl;
retval = 1;
}
return retval;
}
cv::Mat LogMagnitude(cv::Mat cpx)
{
cv::Mat reim[2];
assert(cpx.channels() == 2);
split(cpx, reim);
cv::Mat mag;
magnitude(reim[0], reim[1], mag);
mag += cv::Scalar::all(1);
log(mag, mag);
mag = mag(cv::Rect(0, 0, mag.cols & -2, mag.rows & -2));
return mag;
}
cv::Mat CompleteFullHermitian(cv::Mat in, cv::Size fullSize)
{
assert(in.type() == CV_32FC2);
cv::Mat out(fullSize, CV_32FC2);
for (int i = 0; i < out.rows; ++i)
{
for (int j = 0; j < out.cols; ++j)
{
cv::Vec2f p;
if (j < in.cols)
{
p = in.at<cv::Vec2f>(i, j);
}
else
{
p = in.at<cv::Vec2f>((out.rows - i) % out.rows, (out.cols - j) % out.cols);
p[1] = -p[1];
}
out.at<cv::Vec2f>(i, j) = p;
}
}
return out;
}
cv::Mat InplaceFFTShift(cv::Mat mag)
{
int cx = mag.cols / 2;
int cy = mag.rows / 2;
cv::Mat qTL(mag, cv::Rect(0, 0, cx, cy));
cv::Mat qTR(mag, cv::Rect(cx, 0, cx, cy));
cv::Mat qBL(mag, cv::Rect(0, cy, cx, cy));
cv::Mat qBR(mag, cv::Rect(cx, cy, cx, cy));
cv::Mat tmp;
qTL.copyTo(tmp);
qBR.copyTo(qTL);
tmp.copyTo(qBR);
qTR.copyTo(tmp);
qBL.copyTo(qTR);
tmp.copyTo(qBL);
return mag;
}