Initial commit
This commit is contained in:
commit
7cdac8ded9
45 changed files with 7275 additions and 0 deletions
233
FFT.cpp
Normal file
233
FFT.cpp
Normal file
|
|
@ -0,0 +1,233 @@
|
|||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// File : FFT.cpp
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// LumosQuad - A Lightning Generator
|
||||
// Copyright 2007
|
||||
// The University of North Carolina at Chapel Hill
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// The University of North Carolina at Chapel Hill makes no representations
|
||||
// about the suitability of this software for any purpose. It is provided
|
||||
// "as is" without express or implied warranty.
|
||||
//
|
||||
// Permission to use, copy, modify and distribute this software and its
|
||||
// documentation for educational, research and non-profit purposes, without
|
||||
// fee, and without a written agreement is hereby granted, provided that the
|
||||
// above copyright notice and the following three paragraphs appear in all
|
||||
// copies.
|
||||
//
|
||||
// THE UNIVERSITY OF NORTH CAROLINA SPECIFICALLY DISCLAIM ANY WARRANTIES,
|
||||
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
// FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN
|
||||
// "AS IS" BASIS, AND THE UNIVERSITY OF NORTH CAROLINA HAS NO OBLIGATION TO
|
||||
// PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
//
|
||||
// Please send questions and comments about LumosQuad to kim@cs.unc.edu.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// This program uses OpenEXR, which has the following restrictions:
|
||||
//
|
||||
// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
|
||||
// Digital Ltd. LLC
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Industrial Light & Magic nor the names of
|
||||
// its contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
|
||||
#include "FFT.h"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Construction/Destruction
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
FFT::FFT()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
FFT::~FFT()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool FFT::convolve(float* source, float* kernel, int xSource, int ySource, int xKernel, int yKernel)
|
||||
{
|
||||
int x, y, index;
|
||||
|
||||
// get normalization params
|
||||
float maxCurrent = 0.0f;
|
||||
for (x = 0; x < xSource * ySource; x++)
|
||||
maxCurrent = (maxCurrent < source[x]) ? source[x] : maxCurrent;
|
||||
float maxKernel = 0.0f;
|
||||
for (x = 0; x < xKernel * yKernel; x++)
|
||||
maxKernel = (maxKernel < kernel[x]) ? kernel[x] : maxKernel;
|
||||
float maxProduct = maxCurrent * maxKernel;
|
||||
|
||||
// retrieve dimensions
|
||||
int xHalf = xKernel / 2;
|
||||
int yHalf = yKernel / 2;
|
||||
int xResPadded = xSource + xKernel;
|
||||
int yResPadded = ySource + yKernel;
|
||||
|
||||
if (xResPadded != yResPadded)
|
||||
(xResPadded > yResPadded) ? yResPadded = xResPadded : xResPadded = yResPadded;
|
||||
|
||||
// create padded field
|
||||
fftw_complex* padded = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * xResPadded * yResPadded);
|
||||
if (!padded)
|
||||
{
|
||||
cout << " IMAGE: Not enough memory! Try a smaller final image size." << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// init padded field
|
||||
for (index = 0; index < xResPadded * yResPadded; index++)
|
||||
padded[index][0] = padded[index][1] = 0.0f;
|
||||
index = 0;
|
||||
for (y = 0; y < ySource; y++)
|
||||
for (x = 0; x < xSource; x++, index++)
|
||||
{
|
||||
int paddedIndex = (x + xKernel / 2) + (y + yKernel / 2) * xResPadded;
|
||||
padded[paddedIndex][0] = source[index];
|
||||
}
|
||||
|
||||
// create padded filter
|
||||
fftw_complex* filter = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * xResPadded * yResPadded);
|
||||
if (!filter)
|
||||
{
|
||||
cout << " FILTER: Not enough memory! Try a smaller final image size." << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// init padded filter
|
||||
for (index = 0; index < xResPadded * yResPadded; index++)
|
||||
filter[index][0] = filter[index][1] = 0.0f;
|
||||
|
||||
// quadrant IV
|
||||
for (y = 0; y < (yHalf + 1); y++)
|
||||
for (x = 0; x < (xHalf + 1); x++)
|
||||
{
|
||||
int filterIndex = x + xHalf + y * xKernel;
|
||||
int fieldIndex = x + (y + yResPadded - (yHalf + 1)) * xResPadded;
|
||||
filter[fieldIndex][0] = kernel[filterIndex];
|
||||
}
|
||||
|
||||
// quadrant I
|
||||
for (y = 0; y < yHalf; y++)
|
||||
for (x = 0; x < (xHalf + 1); x++)
|
||||
{
|
||||
int filterIndex = (x + xHalf) + (y + yHalf + 1) * xKernel;
|
||||
int fieldIndex = x + y * xResPadded;
|
||||
filter[fieldIndex][0] = filter[fieldIndex][1] = kernel[filterIndex];
|
||||
}
|
||||
|
||||
// quadrant III
|
||||
for (y = 0; y < (yHalf + 1); y++)
|
||||
for (x = 0; x < xHalf; x++)
|
||||
{
|
||||
int filterIndex = x + y * xKernel;
|
||||
int fieldIndex = (x + xResPadded - xHalf) + (y + yResPadded - (yHalf + 1)) * xResPadded;
|
||||
filter[fieldIndex][0] = filter[fieldIndex][1] = kernel[filterIndex];
|
||||
}
|
||||
|
||||
// quadrant II
|
||||
for (y = 0; y < yHalf; y++)
|
||||
for (x = 0; x < xHalf; x++)
|
||||
{
|
||||
int filterIndex = x + (y + yHalf + 1) * xKernel;
|
||||
int fieldIndex = (x + xResPadded - xHalf) + y * xResPadded;
|
||||
filter[fieldIndex][0] = filter[fieldIndex][1] = kernel[filterIndex];
|
||||
}
|
||||
|
||||
// perform forward FFT on field
|
||||
fftw_complex* paddedTransformed = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * xResPadded * yResPadded);
|
||||
if (!paddedTransformed)
|
||||
{
|
||||
cout << " T-IMAGE: Not enough memory! Try a smaller final image size." << endl;
|
||||
return false;
|
||||
}
|
||||
fftw_plan forwardField = fftw_plan_dft_2d(xResPadded, yResPadded, padded, paddedTransformed, FFTW_FORWARD, FFTW_ESTIMATE);
|
||||
fftw_execute(forwardField);
|
||||
|
||||
// perform forward FFT on filter
|
||||
fftw_complex* filterTransformed = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * xResPadded * yResPadded);
|
||||
if (!filterTransformed)
|
||||
{
|
||||
cout << " T-FILTER: Not enough memory! Try a smaller final image size." << endl;
|
||||
return false;
|
||||
}
|
||||
fftw_plan forwardFilter = fftw_plan_dft_2d(xResPadded, yResPadded, filter, filterTransformed, FFTW_FORWARD, FFTW_ESTIMATE);
|
||||
fftw_execute(forwardFilter);
|
||||
|
||||
// apply frequency space filter
|
||||
for (index = 0; index < xResPadded * yResPadded; index++)
|
||||
{
|
||||
float newReal = paddedTransformed[index][0] * filterTransformed[index][0] -
|
||||
paddedTransformed[index][1] * filterTransformed[index][1];
|
||||
float newIm = paddedTransformed[index][0] * filterTransformed[index][1] +
|
||||
paddedTransformed[index][1] * filterTransformed[index][0];
|
||||
paddedTransformed[index][0] = newReal;
|
||||
paddedTransformed[index][1] = newIm;
|
||||
}
|
||||
|
||||
// transform back
|
||||
fftw_plan backwardField = fftw_plan_dft_2d(xResPadded, yResPadded, paddedTransformed, padded, FFTW_BACKWARD, FFTW_ESTIMATE);
|
||||
fftw_execute(backwardField);
|
||||
|
||||
// copy back into padded
|
||||
index = 0;
|
||||
for (y = 0; y < ySource; y++)
|
||||
for (x = 0; x < xSource; x++, index++)
|
||||
{
|
||||
int paddedIndex = (x + xKernel / 2) + (y + yKernel / 2) * xResPadded;
|
||||
source[index] = padded[paddedIndex][0];
|
||||
}
|
||||
|
||||
// clean up
|
||||
fftw_free(padded);
|
||||
fftw_free(paddedTransformed);
|
||||
fftw_free(filter);
|
||||
fftw_free(filterTransformed);
|
||||
|
||||
// if normalization is exceeded, renormalize
|
||||
float newMax = 0.0f;
|
||||
for (x = 0; x < xSource * ySource; x++)
|
||||
newMax = (newMax < source[x]) ? source[x] : newMax;
|
||||
if (newMax > maxProduct)
|
||||
{
|
||||
float scale = maxProduct / newMax;
|
||||
for (x = 0; x < xSource * ySource; x++)
|
||||
source[x] *= scale;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue