The 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.
29 #include <opencv2/core/version.hpp>
30 #if CV_MAJOR_VERSION >= 3
31 # include <opencv2/imgcodecs.hpp>
33 # include <opencv2/highgui/highgui.hpp>
46 #define CHECK_STATUS(STMT) \
49 VPIStatus status = (STMT); \
50 if (status != VPI_SUCCESS) \
52 char buffer[VPI_MAX_STATUS_MESSAGE_LENGTH]; \
53 vpiGetLastStatusMessage(buffer, sizeof(buffer)); \
54 std::ostringstream ss; \
55 ss << vpiStatusGetName(status) << ": " << buffer; \
56 throw std::runtime_error(ss.str()); \
61 cv::Mat LogMagnitude(cv::Mat cpx);
62 cv::Mat CompleteFullHermitian(cv::Mat in, cv::Size fullSize);
63 cv::Mat InplaceFFTShift(cv::Mat mag);
65 int main(
int argc,
char *argv[])
79 throw std::runtime_error(std::string(
"Usage: ") + argv[0] +
" <cpu|cuda> <input image>");
82 std::string strBackend = argv[1];
83 std::string strInputFileName = argv[2];
86 cv::Mat cvImage = cv::imread(strInputFileName, cv::IMREAD_GRAYSCALE);
89 throw std::runtime_error(
"Can't open '" + strInputFileName +
"'");
92 assert(cvImage.type() == CV_8UC1);
97 if (strBackend ==
"cpu")
101 else if (strBackend ==
"cuda")
107 throw std::runtime_error(
"Backend '" + strBackend +
"' not recognized, it must be either cpu or cuda.");
117 memset(&imgData, 0,
sizeof(imgData));
148 CHECK_STATUS(
vpiSubmitFFT(stream, fft, imageF32, spectrum, 0));
166 cv::Mat mag = InplaceFFTShift(LogMagnitude(CompleteFullHermitian(cvSpectrum, cvImage.size())));
169 normalize(mag, mag, 0, 255, cv::NORM_MINMAX);
172 imwrite(
"spectrum_" + strBackend +
".png", mag);
178 catch (std::exception &e)
180 std::cerr << e.what() << std::endl;
206 cv::Mat LogMagnitude(cv::Mat cpx)
210 assert(cpx.channels() == 2);
215 magnitude(reim[0], reim[1], mag);
218 mag += cv::Scalar::all(1);
220 mag = mag(cv::Rect(0, 0, mag.cols & -2, mag.rows & -2));
225 cv::Mat CompleteFullHermitian(cv::Mat in, cv::Size fullSize)
227 assert(in.type() == CV_32FC2);
229 cv::Mat out(fullSize, CV_32FC2);
230 for (
int i = 0; i < out.rows; ++i)
232 for (
int j = 0; j < out.cols; ++j)
237 p = in.at<cv::Vec2f>(i, j);
241 p = in.at<cv::Vec2f>((out.rows - i) % out.rows, (out.cols - j) % out.cols);
244 out.at<cv::Vec2f>(i, j) = p;
251 cv::Mat InplaceFFTShift(cv::Mat mag)
257 int cx = mag.cols / 2;
258 int cy = mag.rows / 2;
259 cv::Mat qTL(mag, cv::Rect(0, 0, cx, cy));
260 cv::Mat qTR(mag, cv::Rect(cx, 0, cx, cy));
261 cv::Mat qBL(mag, cv::Rect(0, cy, cx, cy));
262 cv::Mat qBR(mag, cv::Rect(cx, cy, cx, cy));