gfourier.cpp

来自「一个由Mike Gashler完成的机器学习方面的includes neural」· C++ 代码 · 共 420 行

CPP
420
字号
/*	Copyright (C) 2006, Mike Gashler	This library is free software; you can redistribute it and/or	modify it under the terms of the GNU Lesser General Public	License as published by the Free Software Foundation; either	version 2.1 of the License, or (at your option) any later version.	see http://www.gnu.org/copyleft/lesser.html*/#include "GFourier.h"#include <math.h>#include "GMacros.h"#include "GImage.h"#include "GBits.h"inline int ReverseBits(int nValue, int nBits){    int n;	int nReversed = 0;    for(n = 0; n < nBits; n++)    {        nReversed = (nReversed << 1) | (nValue & 1);        nValue >>= 1;    }    return nReversed;}bool GFourier::FFT(int nArraySize, struct ComplexNumber* pComplexNumberArray, bool bForward){	double* pData = (double*)pComplexNumberArray;	// Make sure nArraySize is a power of 2	if(nArraySize & (nArraySize - 1))	{		GAssert(false, "Error, nArraySize must be a power of 2");		return false;	}	// Calculate the Log2 of nArraySize and put it in nBits	int n = 1;	int nBits = 0;	while(n < nArraySize)	{		n = n << 1;		nBits++;	}	// Move the data to it's reversed-bit position	int nTotalSize = nArraySize << 1;	double* pTmp = new double[nArraySize << 1];	int nReversed;	for(n = 0; n < nArraySize; n++)	{		nReversed = ReverseBits(n, nBits);		pTmp[nReversed << 1] = pData[n << 1];		pTmp[(nReversed << 1) + 1] = pData[(n << 1) + 1];	}	for(n = 0; n < nTotalSize; n++)		pData[n] = pTmp[n];	delete(pTmp);	// Calculate the angle numerator	double dAngleNumerator;	if(bForward)		dAngleNumerator = -2.0 * PI;	else		dAngleNumerator = 2.0 * PI;	// Do the Fast Forier Transform	double dR0, dR1, dR2, dR3, dI0, dI1, dI2, dI3;	int n2;	int nStart;	int nHalfBlockSize;	for(nHalfBlockSize = 1; nHalfBlockSize < nArraySize; nHalfBlockSize = nHalfBlockSize << 1)	{		// Calculate angles, sines, and cosines		double dAngleDelta = dAngleNumerator / ((double)(nHalfBlockSize << 1));		double dCos1 = cos(-dAngleDelta);		double d2Cos1 = 2 * dCos1; // So we don't have to calculate this a bunch of times		double dCos2 = cos(-2 * dAngleDelta);		double dSin1 = sin(-dAngleDelta);		double dSin2 = sin(-2 * dAngleDelta);		// Do each block		for(nStart = 0; nStart < nArraySize; nStart += (nHalfBlockSize << 1))		{			dR1 = dCos1;			dR2 = dCos2;			dI1 = dSin1;			dI2 = dSin2;			int nEnd = nStart + nHalfBlockSize;			for(n = nStart; n < nEnd; n++)			{				dR0 = d2Cos1 * dR1 - dR2;				dR2 = dR1;				dR1 = dR0;				dI0 = d2Cos1 * dI1 - dI2;				dI2 = dI1;				dI1 = dI0;				n2 = n + nHalfBlockSize;				dR3 = dR0 * pData[n2 << 1] - dI0 * pData[(n2 << 1) + 1];				dI3 = dR0 * pData[(n2 << 1) + 1] + dI0 * pData[n2 << 1];				pData[n2 << 1] = pData[n << 1] - dR3;				pData[(n2 << 1) + 1] = pData[(n << 1) + 1] - dI3;				pData[n << 1] += dR3;				pData[(n << 1) + 1] += dI3;			}		}	}	// Normalize output if we're doing the inverse forier transform	if(!bForward)	{		for(n = 0; n < nTotalSize; n++)			pData[n] /= (double)nArraySize;	}	return true;}bool GFourier::FFT2D(int nArrayWidth, int nArrayHeight, struct ComplexNumber* p2DComplexNumberArray, bool bForward){	double* pData = (double*)p2DComplexNumberArray;	double* pTmpArray = new double[MAX(nArrayWidth, nArrayHeight) << 1];	ArrayHolder<double*> hTmpArray(pTmpArray);	int x, y;	// Horizontal transforms	for(y = 0; y < nArrayHeight; y++)	{		for(x = 0; x < nArrayWidth; x++)		{			pTmpArray[x << 1] = pData[(nArrayWidth * y + x) << 1];			pTmpArray[(x << 1) + 1] = pData[((nArrayWidth * y + x) << 1) + 1];		}		if(!FFT(nArrayWidth, (struct ComplexNumber*)pTmpArray, bForward))			return false;		for(x = 0; x < nArrayWidth; x++)		{			pData[(nArrayWidth * y + x) << 1] = pTmpArray[x << 1];			pData[((nArrayWidth * y + x) << 1) + 1] = pTmpArray[(x << 1) + 1];		}	}	// Vertical transforms	for(x = 0; x < nArrayWidth; x++)	{		for(y = 0; y < nArrayHeight; y++)		{			pTmpArray[y << 1] = pData[(nArrayWidth * y + x) << 1];			pTmpArray[(y << 1) + 1] = pData[((nArrayWidth * y + x) << 1) + 1];		}		if(!FFT(nArrayHeight, (struct ComplexNumber*)pTmpArray, bForward))			return false;		for(y = 0; y < nArrayHeight; y++)		{			pData[(nArrayWidth * y + x) << 1] = pTmpArray[y << 1];			pData[((nArrayWidth * y + x) << 1) + 1] = pTmpArray[(y << 1) + 1];		}	}	return true;}// staticstruct ComplexNumber* GFourier::ImageToFFTArray(GImage* pImage, int* pWidth, int* pOneThirdHeight){	int x, y;	int width = pImage->GetWidth();	int height = pImage->GetHeight();	int wid = GBits::GetBoundingPowerOfTwo(width);	int hgt = GBits::GetBoundingPowerOfTwo(height);	struct ComplexNumber* pArray = new struct ComplexNumber[3 * wid * hgt];	int pos = 0;
	// Red channel
	for(y = 0; y < height; y++)	{		for(x = 0; x < width; x++)		{			pArray[pos].real = gRed(pImage->GetPixel(x, y));			pArray[pos].imag = 0;			pos++;		}		for(; x < wid; x++)		{			pArray[pos].real = 0;			pArray[pos].imag = 0;			pos++;		}	}	for(; y < hgt; y++)	{		for(x = 0; x < wid; x++)		{			pArray[pos].real = 0;			pArray[pos].imag = 0;			pos++;		}	}

	// Green channel
	int nGreenStart = pos;	for(y = 0; y < height; y++)
	{
		for(x = 0; x < width; x++)
		{
			pArray[pos].real = gGreen(pImage->GetPixel(x, y));
			pArray[pos].imag = 0;
			pos++;
		}
		for(; x < wid; x++)
		{
			pArray[pos].real = 0;
			pArray[pos].imag = 0;
			pos++;
		}
	}
	for(; y < hgt; y++)
	{
		for(x = 0; x < wid; x++)
		{
			pArray[pos].real = 0;
			pArray[pos].imag = 0;
			pos++;
		}
	}

	// Blue channel
	int nBlueStart = pos;
	for(y = 0; y < height; y++)
	{
		for(x = 0; x < width; x++)
		{
			pArray[pos].real = gBlue(pImage->GetPixel(x, y));
			pArray[pos].imag = 0;
			pos++;
		}
		for(; x < wid; x++)
		{
			pArray[pos].real = 0;
			pArray[pos].imag = 0;
			pos++;
		}
	}
	for(; y < hgt; y++)
	{
		for(x = 0; x < wid; x++)
		{
			pArray[pos].real = 0;
			pArray[pos].imag = 0;
			pos++;
		}
	}

	// Convert to the Fourier domain
	if(!GFourier::FFT2D(wid, hgt, pArray, true))
	{
		delete[] pArray;
		return NULL;
	}
	if(!GFourier::FFT2D(wid, hgt, &pArray[nGreenStart], true))
	{
		delete[] pArray;
		return NULL;
	}
	if(!GFourier::FFT2D(wid, hgt, &pArray[nBlueStart], true))
	{
		delete[] pArray;
		return NULL;
	}

	*pWidth = wid;	*pOneThirdHeight = hgt;	return pArray;}// staticvoid GFourier::FFTArrayToImage(struct ComplexNumber* pArray, int width, int oneThirdHeight, GImage* pImage, bool normalize){	// Convert to the Spatial domain
	int nGreenStart = width * oneThirdHeight;
	int nBlueStart = nGreenStart + nGreenStart;
	if(!GFourier::FFT2D(width, oneThirdHeight, pArray, false))
	{
		GAssert(false, "something's wrong");
		return;
	}
	if(!GFourier::FFT2D(width, oneThirdHeight, &pArray[nGreenStart], false))
	{
		GAssert(false, "something's wrong");
		return;
	}
	if(!GFourier::FFT2D(width, oneThirdHeight, &pArray[nBlueStart], false))
	{
		GAssert(false, "something's wrong");
		return;
	}

	// Copy the data back into the image
	int nWid = pImage->GetWidth();
	int nHgt = pImage->GetHeight();
	int x, y;	double min = 0;	double max = (double)256;	if(normalize)	{		min = pArray[0].real;		max = min;		double d;		for(y = 0; y < nHgt; y++)		{			for(x = 0; x < nWid; x++)			{				d = pArray[width * y + x].real;				if(d < min)					min = d;				else if(d > max)					max = d;				d = pArray[nGreenStart + width * y + x].real;
				if(d < min)
					min = d;
				else if(d > max)
					max = d;
				d = pArray[nBlueStart + width * y + x].real;
				if(d < min)
					min = d;
				else if(d > max)
					max = d;
			}		}	}	double scale = (double)256 / (max - min);	for(y = 0; y < nHgt; y++)	{		for(x = 0; x < nWid; x++)		{			pImage->SetPixel(x, y, gARGB(0xff,						ClipChan((int)((pArray[width * y + x].real - min) * scale)),						ClipChan((int)((pArray[nGreenStart + width * y + x].real - min) * scale)),						ClipChan((int)((pArray[nBlueStart + width * y + x].real - min) * scale))					));		}	}}#ifndef NO_TEST_CODEvoid GFourier::Test(){	struct ComplexNumber cn[4];	cn[0].real = 1;	cn[0].imag = 0;	cn[1].real = 1;	cn[1].imag = 0;	cn[2].real = 1;	cn[2].imag = 0;	cn[3].real = 1;	cn[3].imag = 0;	GFourier::FFT(4, cn, true);	if(cn[0].real != 4)		throw "wrong answer";	if(cn[0].imag != 0)		throw "wrong answer";	int n;	for(n = 1; n < 3; n++)	{		if(cn[n].real != 0)			throw "wrong answer";		if(cn[n].imag != 0)			throw "wrong answer";	}	GFourier::FFT(4, cn, false);	for(n = 0; n < 3; n++)	{		if(cn[n].real != 1)			throw "wrong answer";		if(cn[n].imag != 0)			throw "wrong answer";	}}/*void GFourier::Test(){	struct ComplexNumber cn[4];	cn[0].real = 1;	cn[0].imag = 0;	cn[1].real = 0;	cn[1].imag = 0;	cn[2].real = 0;	cn[2].imag = 0;	cn[3].real = 0;	cn[3].imag = 0;	GFourier::FFT(4, cn, true);	int n;	for(n = 0; n < 4; n++)	{		if(cn[n].real != 1)			throw "wrong answer";		if(cn[n].imag != 0)			throw "wrong answer";	}	GFourier::FFT(4, cn, false);	if(cn[0].real != 1)		throw "wrong answer";	if(cn[0].imag != 0)		throw "wrong answer";	for(n = 1; n < 4; n++)	{		if(cn[n].real != 0)			throw "wrong answer";		if(cn[n].imag != 0)			throw "wrong answer";	}}*/#endif // NO_TEST_CODE

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?