I want to calculate the frequency of time series precisely with at least 3 decimal value.
This is a simple example that calculates the frequency of integer values.
#include <fftw3.h>
#include <cstdio>
#include <cmath>
#include <iostream>
#include <fstream>
#define REAL 0
#define IMAG 1
#define NUM_POINTS 1024
void acquire_signal(double *signal, double *theta) {
/* Generate two sine waves of different frequencies and
* amplitudes.
*/
int i;
for (i = 0; i < NUM_POINTS; ++i) {
theta[i] = (double)i / (double)NUM_POINTS;
signal[i] = 1.0*sin(50.0 * 2.0 * M_PI * theta[i]) +
0.5*sin(80.0 * 2.0 * M_PI * theta[i]);
}
}
int main() {
unsigned flags{0};
double *theta = new double[NUM_POINTS];
double *signal = new double[NUM_POINTS];
fftw_complex result[NUM_POINTS/2+1];
fftw_plan plan = fftw_plan_dft_r2c_1d(NUM_POINTS,
signal,
result,
flags);
acquire_signal(signal,theta);
fftw_execute(plan);
//save signal and result
std::ofstream f1,f2;
f1.open ("signal.txt");
for (int i=0; i<NUM_POINTS; i++){
f1 <<theta[i]<<" "<<signal[i]<<"\n";
}
f1.close();
f2.open("result.txt");
for (int i=0; i<NUM_POINTS/2; i++){
double yf = 2.0/(double)(NUM_POINTS)* sqrt(result[i][REAL]*result[i][REAL]+ result[i][IMAG]* result[i][IMAG]);
f2<< (double)i << " "<<yf <<"\n";
}
f2.close();
fftw_destroy_plan(plan);
delete[] signal,theta;
return 0;
}
But how should I change the code if I have
signal = 1.0*sin(50.350 * 2.0 * M_PI * theta[i]) +
0.5*sin(80.455 * 2.0 * M_PI * theta[i]);
Is it appropriate to change the units of time and frequency?
for example time in 1000*s and frequency in kHz?
Just changing the numbers in sin will shift your lines from 50 and 80 to 50.350 and 80.455 Hz, and assuming you have 1024 lines by 1024 Hz. But you still have 1Hz resolution. You need more lines (x1000) by the same sampling frequency to get bigger resolution.
For example if you want 1/4 Hz resolution you need 4x more samples so by 1024 Hz sample rate you need fs * 4 samples:
...
#define NUM_POINTS (1024 * 4)
double fs = 1024; // Sample rate in Hz
void acquire_signal(double *signal, double *theta) {
/* Generate two sine waves of different frequencies and
* amplitudes.
*/
int i;
for (i = 0; i < NUM_POINTS; ++i) {
theta[i] = (double)i / (double)fs;
signal[i] = 1.0*sin(50.0 * 2.0 * M_PI * theta[i]) +
0.5*sin(80.0 * 2.0 * M_PI * theta[i]);
}
}
....
for (int i=0; i< (NUM_POINTS/2 + 1) ; i++){
double yf = 2.0/(double)(NUM_POINTS)* sqrt(result[i][REAL]*result[i][REAL]+ result[i][IMAG]* result[i][IMAG]);
f2 << (double)i * fs / ( NUM_POINTS ) << " "<<yf <<"\n";
}
0 2.90715e-16
0.25 1.19539e-16
0.5 2.15565e-16
0.75 2.88629e-16
1 3.05084e-16
1.25 3.864e-16
...
49.75 9.47968e-16
50 1
50.25 1.12861e-15
50.5 4.95946e-16
50.75 6.9016e-16
...
Related
I have been working on creating a mixed wave signal. My code is in c++ :
Server signal:
void server_sineWave(BitDepth buffer[], double sin_freq, double beep_freq) {
BitDepth amplitude = std::numeric_limits<BitDepth>::max() * 0.5;
QWORD c = 0;
double d = (samplerate / sin_freq);
int initial = NUM_SAMPLES / 25;
for (QWORD i = 0; i < NUM_SAMPLES; i += channels) {
buffer[i] = amplitude * sin((2 * pi * sin_freq * i) / samplerate); // sin wave generated at "freq"
if (i == initial) {
for (QWORD j = 0; j < 480; j++) {
double stream = amplitude * sin((2 * pi * sin_freq * i / samplerate));
double beep = amplitude * sin((2 * pi * beep_freq * j / samplerate));
double multiplier = .4 * (1 - cos(2 * pi * j / 480));
buffer[i] = stream + (beep * multiplier);
i++;
}
initial = i + 19200.0;
}
}
}
Client signal:
void client_sineWave(BitDepth buffer[], double sin_freq, double beep_freq) {
BitDepth amplitude = std::numeric_limits<BitDepth>::max() * 0.5;
QWORD c = 0;
double d = (samplerate / sin_freq);
int initial = NUM_SAMPLES / 25;
for (QWORD i = 0; i < NUM_SAMPLES; i += channels) {
buffer[i] = amplitude * sin(2 * pi * sin_freq * i / samplerate); // sin wave generated at "freq"
if (i == initial) {
for (QWORD j = 0; j < 480; j++) {
double stream = amplitude * sin((2 * pi * sin_freq * i / samplerate));
double beep = amplitude * sin((2 * pi * beep_freq * j / samplerate));
double multiplier = .4 * (1 - cos(2 * pi * j / 480));
buffer[i] = stream + (beep * multiplier);
// buffer[i] += (beep * multiplier);
i++;
}
initial = i + 19200.0;
//(1000 + rand() % 10000)
//double deg = 360.0 / d;
//buffer[i] = buffer[i + (1 * (channels - 1))] = sin((c++ * deg) * pi / 180) * amplitude;
}
}
}
Mixing of server and client signals:
void mix(BitDepth buffer[], BitDepth server[], BitDepth client[], double duration_milliseconds) {
QWORD num_samples = duration_milliseconds * (NUM_SAMPLES / 10000.0);
double tmp = 0;
QWORD size = NUM_SAMPLES + num_samples;
BitDepth *server_delay = new BitDepth[size];
BitDepth *client_delay = new BitDepth[size];
for (QWORD i = 0; i < size; i++) {
if (i < num_samples) {
server_delay[i] = 0;
client_delay[i + NUM_SAMPLES] = 0;
}
if (i > num_samples) {
server_delay[i] = server[i - num_samples];
client_delay[i - num_samples] = client[i - num_samples];
}
}
for (QWORD i = 0; i < NUM_SAMPLES; i += channels) {
// double multiplier = .5 * (1 - cos(2 * pi * i / NUM_SAMPLES-1));
// double multiplier = (0.54 - 0.46 * cos(2.0 * M_PI * (double) i / (double) (NUM_SAMPLES - 1)));
// server_delay[i] = multiplier * (server_delay[i]);
// client_delay[i] = multiplier * (client_delay[i]);
tmp = server_delay[i] + client_delay[i];
if (tmp > 32767) {
tmp = 32767;
} else if (tmp < -32768) {
tmp = -32768;
}
buffer[i] = tmp;
}
}
My Result in spectrogram from the above code:
Now, when I change the amplitude by increasing value from 0.5 to 0.8, in the following line:
BitDepth amplitude = std::numeric_limits<BitDepth>::max() * 0.5;
to
BitDepth amplitude = std::numeric_limits<BitDepth>::max() * 0.8;
I get following result:
I am new in DSP c++ programming and I really don't know what is this issue and how to resolve this issue?
Please help me in solving this issue.
thanks.
As Suggested by #PaulR, clipping was causing a lot of harmonics.
Your waveform is clipping (because 0.8 + 0.8 > 1.0), which will generate a lot of harmonics - look at the data in your debugger and you’ll see lots of flat peaks at +/- 32k.
So, after taking care of this limit. My issue is resolved.
Thanks alot.
I'm trying to understand why computing determinant of a 3x3 matrix in this way gives broken results:
#include <iostream>
#include <array>
#include <vector>
int main(int argc, char const *argv[])
{
const int dim = 3;
std::vector<std::vector<float>> data;
data.resize(dim, std::vector<float>(dim, 0));
std::array<float, dim*dim> myArray = {
-1000.0, -1000.0, -1000.0,
-1000.0, -1000.0, -1000.0,
-1000.0, -1000.0, -999.0
};
for(int i = 0; i < dim; i++){
for(int j = 0; j < dim; j++){
data[i][j] = myArray[dim*i + j];
}
}
float det =
data[0][0] * data[1][1] * data[2][2] +
data[0][1] * data[1][2] * data[2][0] +
data[0][2] * data[2][1] * data[1][0] -
data[2][0] * data[1][1] * data[0][2] -
data[0][0] * data[1][2] * data[2][1] -
data[1][0] * data[0][1] * data[2][2];
float anotherDet = 0;
for(int i = 0; i < 2; i++){
anotherDet = anotherDet + 1000 * 1000 * 1000;
}
for(int i = 0; i < 2; i++){
anotherDet = anotherDet - 1000 * 1000 * 1000;
}
anotherDet = anotherDet - 1000 * 1000 * 999;
anotherDet = anotherDet + 1000 * 1000 * 999;
std::cout << det << " " << anotherDet << std::endl;
return 0;
}
The output of this code is -64 0, whereas the real determinant of such matrix should be zero. My suspicion is that the error is related to the floating points precision, but I still don't get the logic for why such discrepancies happen.
I tried debugging, and indeed I found that there is a rounding error that gets carried on. -2999000060 is the value of det in the middle of that large sum.
But if I try the following:
float det2 =
1000 * 1000 * 1000 +
1000 * 1000 * 1000 +
1000 * 1000 * 999 -
1000 * 1000 * 1000 -
1000 * 1000 * 1000 -
1000 * 1000 * 999;
It gives the correct value of 0, but only because its an arithmetic operation, and thus there are not rounding errors.
Edit: I understand now how operations with floats that big could carry some rounding error.
Please see the Edits in the answer below this question.
I have written a script to plot the frequency spectrum of a sinusoidal signal with c++. Here are the steps
Applying Hanning window
Apply FFT using fftw3 library
I have three graphs: Signal, Signal when is multiplied to Hanning function, and the frequency spectrum. The frequency spectrum looks wrong. It should have a peak at 50 Hz. Any suggestion would be appreciated. Here is the code:
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <fftw3.h>
#include <iostream>
#include <cmath>
#include <fstream>
using namespace std;
int main()
{
int i;
double y;
int N=50;
double Fs=1000;//sampling frequency
double T=1/Fs;//sample time
double f=50;//frequency
double *in;
fftw_complex *out;
double t[N];//time vector
double ff[N];
fftw_plan plan_forward;
in = (double*) fftw_malloc(sizeof(double) * N);
out = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * N);
for (int i=0; i< N;i++)
{
t[i]=i*T;
ff[i]=1/t[i];
in[i] =0.7 *sin(2*M_PI*f*t[i]);// generate sine waveform
double multiplier = 0.5 * (1 - cos(2*M_PI*i/(N-1)));//Hanning Window
in[i] = multiplier * in[i];
}
plan_forward = fftw_plan_dft_r2c_1d ( N, in, out, FFTW_ESTIMATE );
fftw_execute ( plan_forward );
double v[N];
for (int i = 0; i < N; i++)
{
v[i]=20*log(sqrt(out[i][0]*out[i][0]+ out[i][1]*out[i][1])/N/2);//Here I have calculated the y axis of the spectrum in dB
}
fstream myfile;
myfile.open("example2.txt",fstream::out);
myfile << "plot '-' using 1:2" << std::endl;
for(i = 0; i < N; ++i)
{
myfile << ff[i]<< " " << v[i]<< std::endl;
}
myfile.close();
fftw_destroy_plan ( plan_forward );
fftw_free ( in );
fftw_free ( out );
return 0;
}
I have to add that I have plotted the graphs using gnuplot after inserting the results into example2.txt. So ff[i] vs v[i] should give me the frequency spectrum.
Here are the plots: Frequency Spectrum and Sinusoidal time Window respectively:
My Frequency intervals were completely wrong. According to http://www.ni.com/white-paper/3995/en/#toc1; the frequency range and resolution on the x-axis depend on sampling rate and N. The last point on the frequency axis should be Fs/2-Fs/N and the resolution dF=FS/N.So I have changed my script to: (since frequency resolution is Fs/N as you increase the number of smaples N (or decrease sampling frequency Fs) you get smaller frequency resolution and better results.)
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <fftw3.h>
#include <iostream>
#include <cmath>
#include <fstream>
using namespace std;
int main()
{
int i;
double y;
int N=550;//Number of points acquired inside the window
double Fs=200;//sampling frequency
double dF=Fs/N;
double T=1/Fs;//sample time
double f=50;//frequency
double *in;
fftw_complex *out;
double t[N];//time vector
double ff[N];
fftw_plan plan_forward;
in = (double*) fftw_malloc(sizeof(double) * N);
out = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * N);
for (int i=0; i<= N;i++)
{
t[i]=i*T;
in[i] =0.7 *sin(2*M_PI*f*t[i]);// generate sine waveform
double multiplier = 0.5 * (1 - cos(2*M_PI*i/(N-1)));//Hanning Window
in[i] = multiplier * in[i];
}
for (int i=0; i<= ((N/2)-1);i++)
{ff[i]=Fs*i/N;
}
plan_forward = fftw_plan_dft_r2c_1d ( N, in, out, FFTW_ESTIMATE );
fftw_execute ( plan_forward );
double v[N];
for (int i = 0; i<= ((N/2)-1); i++)
{
v[i]=(20*log(sqrt(out[i][0]*out[i][0]+ out[i][1]*out[i][1])))/N; //Here I have calculated the y axis of the spectrum in dB
}
fstream myfile;
myfile.open("example2.txt",fstream::out);
myfile << "plot '-' using 1:2" << std::endl;
for(i = 0;i< ((N/2)-1); i++)
{
myfile << ff[i]<< " " << v[i]<< std::endl;
}
myfile.close();
fftw_destroy_plan ( plan_forward );
fftw_free ( in );
fftw_free ( out );
return 0;
}
I think you may not have enough samples, particularly, reference this Electronics.StackExhcange post: https://electronics.stackexchange.com/q/12407/84272.
You're sampling for 50 samples, so 25 FFT bins. You're sampling at 1000 Hz, so 1000 / 2 / 25 == 250 Hz per FFT bins. Your bin resolution is too low.
I think you need to lower the sampling frequency or increase the number of samples.
Since your question in on SO, your code could use some indentation and style improvement to make it easier to read.
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <fftw3.h>
#include <iostream>
#include <cmath>
#include <fstream>
using namespace std;
int main(){
// use meaningful names for all the variables
int i;
double y;
int N = 550; // number of points acquired inside the window
double Fs = 200; // sampling frequency
double dF = Fs / N;
double T = 1 / Fs; // sample time
double f = 50; // frequency
double *in;
fftw_complex *out;
double t[N]; // time vector
double ff[N];
fftw_plan plan_forward;
in = (double*) fftw_malloc(sizeof(double) * N);
out = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * N);
for (int i = 0; i <= N; i++){
t[i]=i*T;
in[i] = 0.7 * sin(2 * M_PI * f * t[i]); // generate sine waveform
double multiplier = 0.5 * (1 - cos(2 * M_PI * i / (N-1))); // Hanning Window
in[i] = multiplier * in[i];
}
for(int i = 0; i <= ((N/2)-1); i++){
ff[i] = (Fs * i) / N;
}
plan_forward = fftw_plan_dft_r2c_1d(N, in, out, FFTW_ESTIMATE);
fftw_execute(plan_forward);
double v[N];
// Here I have calculated the y axis of the spectrum in dB
for(int i = 0; i <= ((N/2)-1); i++){
v[i] = (20 * log(sqrt(out[i][0] * out[i][0] + out[i][1] * out[i][1]))) / N;
}
fstream myfile;
myfile.open("example2.txt", fstream::out);
myfile << "plot '-' using 1:2" << std::endl;
for(i = 0; i < ((N/2)-1); i++){
myfile << ff[i] << " " << v[i] << std::endl;
}
myfile.close();
fftw_destroy_plan(plan_forward);
fftw_free(in);
fftw_free(out);
return 0;
}
Your code can use more comments, especially before loops or function calls to specify their input value (purpose) and/or returning value (result).
I implemented my filter, where overlap add method to prevent circular convultion is used.
input - file with noise, output should be filtered file.
My result: out is slightly modified, frequencies aren`t cut
My guess is that I wrongly multiply in the frequency domain input signal on the filter kernel
(My intention is to cut off frequencies that aren't in range [300,3700]). How multiplication should be done?
I construct kernel using blackmanwindow - is my understanding correct? ( I compute amount of frequency per one sample of filter, then go through samples and see if it is in range I want to cut off I calculate frequency using formula for Blackman window.)
I just started learning DSP.
Here is my implementation (what is wrong with it???):
void DeleteFrequencies(char* fileWithNoise, char* resultFile, const int bufferSize, int lowestFrequency, int highestFrequency, int sampleRate )
{
// |1|. files
std::fstream in;
std::fstream out;
in.open (fileWithNoise, std::ios::in | std::ios::binary);
out.open(resultFile, std::ios::out | std::ios::binary);
// |2|. Filter kernel design. I shall use blackman window
// fundamental params
const int filterKernelLength = 200; // 512
const int filterMaxFrequency = sampleRate / 2; // 8000 / 2
const int frequencyPerSamle = filterMaxFrequency / filterKernelLength;
double *RealFilterResp = new double [bufferSize / 2];
double *ImmFilterResp = new double [bufferSize / 2];
// coefficients for Blackman window
const double a0 = 0.42659;
const double a1 = 0.49656;
const double a2 = 0.076849;
// construct filter kernel
for (int i = 0 ; i < bufferSize / 2; ++i)
{
if ( i >= filterKernelLength ) // padd filter kernel with zeroes
{
RealFilterResp[i] = 0;
ImmFilterResp[i] = 0;
}
else if (i * frequencyPerSamle < lowestFrequency || i * frequencyPerSamle > highestFrequency)
{
// apply blackman window (to eleminate frequencies < 300 hz and > 3700 hz)
RealFilterResp[i] = a0 - a1 * cos (2 * M_PI * i / (bufferSize / 2 - 1)) + a2 * cos (4 * M_PI / (bufferSize / 2 - 1));
ImmFilterResp[i] = a0 - a1 * cos (2 * M_PI * i / (bufferSize / 2 - 1)) + a2 * cos (4 * M_PI / (bufferSize / 2 - 1));
}
else
{
RealFilterResp[i] = 1;
ImmFilterResp[i] = 1;
}
}
// |3|. overlap add method
// calculate parameters for overlap add method (we use it to prevent circular convultion)
const int FFT_length = pow (2.0 ,(int)(log(bufferSize + filterKernelLength - 1.0)/log(2.0)) + 1.0);
double *OLAP = new double[bufferSize / 2 ]; // holds the overlapping samples from segment to segment
memset(OLAP,0, bufferSize / 2 * sizeof (double));
double *RealX = new double[bufferSize];
memset(RealX, 0, bufferSize * sizeof(double));
double *ImmX = new double[bufferSize];
memset(ImmX, 0, bufferSize * sizeof(double));
short* audioDataBuffer = new short[bufferSize];
memset(audioDataBuffer, 0 , sizeof(short) * bufferSize);
// start reading from file by chunks of bufferSize
while (in.good())
{
// get proper chunk of data
FillBufferFromFile(audioDataBuffer, bufferSize, in); // read chunk from file
ShortArrayToDoubleArray(audioDataBuffer, RealX, bufferSize); // fill RealPart
ForwardRealFFT(RealX, ImmX, bufferSize); // go to frequency domain
// perform convultion as multiplication in frequency domain
for (int j = 0; j < bufferSize / 2; ++j)
{
double tmp = RealX[j] * RealFilterResp[j] - ImmX[j] * ImmFilterResp[j];
ImmX[j] = RealX[j] * ImmFilterResp[j] + ImmX[j] * RealFilterResp[j];
RealX[j] = tmp;
}
// Inverse FFT
ReverseRealFFT(RealX, ImmX, bufferSize); // go to time domain
// add last segment overlap to this segment
for (int j = 0; j < filterKernelLength - 2; ++j )
{
RealX[j] += OLAP[j];
}
// save samples that will overlap the next segment
for (int j = bufferSize/2 + 1; j < bufferSize; ++j )
{
OLAP[j - bufferSize/2 - 1] = audioDataBuffer[j];
}
// write results
DoubleArrayToShortArray(RealX, audioDataBuffer, bufferSize);
FillFileFromBuffer(audioDataBuffer, bufferSize, out);
}
/*ReverseRealFFT(RealX, ImmX, bufferSize
);
DoubleArrayToShortArray(RealX, audioDataBuffer, bufferSize);*/
delete [] audioDataBuffer;
delete [] RealFilterResp;
delete [] ImmFilterResp;
delete [] OLAP;
delete [] RealX;
delete [] ImmX;
in.close();
out.close();
}
If your intention is to use the window method to implement the filter, the window should multiply the time-domain sequence corresponding to the infinite impulse response of the ideal bandpass filter.
Specifically, for a bandpass filter of bandwidth w0=2*pi*(3700-300)/8000 centered at wc=2*pi*(300+3700)/8000, the ideal impulse response would be (for -infinity < n < infinity):
w0*sinc(0.5*w0*n/pi) * cos(wc*n) / pi
Which you would shift to the interval [0,N-1], and then apply the window that you computed:
double sinc(double x) {
if (fabs(x)<1e-6) return 1.0;
return sin(M_PI * x)/(M_PI * x);
}
void bandpassDesign(int N, double* filterImpulseResponse) {
double w0 = 2*(3700-300)*M_PI/8000;
double wc = 2*(300+3700)*M_PI/8000;
double shift = 0.5*N;
for (int i = 0; i < bufferSize; ++i) {
double truncatedIdealResponse = w0*sinc(0.5*w0*(i-shift)/M_PI) * cos(wc*i) / M_PI;
double window = a0 - a1 * cos (2 * M_PI * i / (N- 1)) + a2 * cos (4 * M_PI * i / (N- 1));
filterImpulseResponse[i] = truncatedIdealResponse * window;
}
}
You can then take the FFT to obtain the frequency-domain coefficients. Remember that if you intend on filtering data using this filter, the time sequence has to be zero padded.
For example, if you wish to use a 1024-point FFT with the overlap-add method, and assuming a 128-point filter kernel meets your filter design specifications, you would call bandpassDesign with N=128, pad with 1024-128=896 zeros, then take the FFT.
Your window coefficients are wrong - the window function is purely real, and you are going to multiply your (complex) frequency domain data with these real coeffs. So your filter coef initialisation:
double *RealFilterResp = new double [bufferSize / 2];
double *ImmFilterResp = new double [bufferSize / 2];
if ( i >= filterKernelLength ) // padd filter kernel with zeroes
{
RealFilterResp[i] = 0;
ImmFilterResp[i] = 0;
}
else if (i * frequencyPerSamle < lowestFrequency || i * frequencyPerSamle > highestFrequency)
{
// apply blackman window (to eleminate frequencies < 300 hz and > 3700 hz)
RealFilterResp[i] = a0 - a1 * cos (2 * M_PI * i / (bufferSize / 2 - 1)) + a2 * cos (4 * M_PI / (bufferSize / 2 - 1));
ImmFilterResp[i] = a0 - a1 * cos (2 * M_PI * i / (bufferSize / 2 - 1)) + a2 * cos (4 * M_PI / (bufferSize / 2 - 1));
}
else
{
RealFilterResp[i] = 1;
ImmFilterResp[i] = 1;
}
should just be:
double *FilterResp = new double [bufferSize / 2];
if ( i >= filterKernelLength ) // padd filter kernel with zeroes
{
FilterResp[i] = 0;
}
else if (i * frequencyPerSamle < lowestFrequency || i * frequencyPerSamle > highestFrequency)
{
FilterResp[i] = a0 - a1 * cos (2 * M_PI * i / (bufferSize / 2 - 1)) + a2 * cos (4 * M_PI / (bufferSize / 2 - 1));
}
else
{
FilterResp[i] = 1;
}
and the frequency domain multiplication:
for (int j = 0; j < bufferSize / 2; ++j)
{
double tmp = RealX[j] * RealFilterResp[j] - ImmX[j] * ImmFilterResp[j];
ImmX[j] = RealX[j] * ImmFilterResp[j] + ImmX[j] * RealFilterResp[j];
RealX[j] = tmp;
}
should just be:
for (int j = 0; j < bufferSize / 2; ++j)
{
RealX[j] *= FilterResp[j];
ImmX[j] *= FilterResp[j];
}
i'm trying to implement Gabor Wavelet feature as described in this paper:
"Texture Features for Browsing and Retrieval of Image Data"
the feature vector is composed from mean and standard deviation (example of feature vector below has scale=4 and orientation=6)
Implementation code:
void gabor_main(int argc, char **argv)
{
int img_height; // height of input image
int img_width; // width of input image
int side; // side (filter dimension = (2*side+1)*(2*side+1)) = 60
int scale; // number of scale
int orientation; // number of orientation
int flag; // flag (removing the DC term) = 0 (False)
FILE* fp;
unsigned char *tmp_raw_img; // temporary raw image data
double Ul; // Uh (highest spatial frequency)
double Uh; // Ul (lowest spatial frequency)
Matrix* img_mat; // input image
Matrix* F_r; // result, real part
Matrix* F_i; // result, imaginary part
Matrix* F_m; // result, magnitude of real part and imaginary part
scale = 4;
orientation = 6;
Ul = 0.1;
Uh = 0.4;
flag = 0;
side = 60;
...
/* ----------------- Reading raw image ----------------- */
...
/* ----------------- Gabor filtered outputs ----------------- */
CreateMatrix(&F_r, img_height * scale, img_width * orientation); // memory allocation of real part matrix of the output
CreateMatrix(&F_i, img_height * scale, img_width * orientation); // memory allocation of imaginary part matrix of the output
CreateMatrix(&F_m, img_height * scale, img_width * orientation); // // memory allocation of magnitude of the output
GaborFilteredImg(F_r, F_i, img_mat, side, Ul, Uh, scale, orientation, flag);
/* ----------------- Compute Feature Vector ----------------- */
// Magnitude of complex value
for (int h = 0; h < (img_height * scale); h++)
{
for (int w = 0; w < (img_width * orientation); w++)
{
F_m->data[h][w] = sqrt(F_r->data[h][w] * F_r->data[h][w] + F_i->data[h][w] * F_i->data[h][w]);
}
}
for(int i = 0; i < scale; i++)
{
for(int j = 0;j < orientation; j++)
{
double avg = Average(F_m, img_height, img_width, i, j);
double std = StandardDeviation(F_m, img_height, img_width, i, j);
// Print the result
std::cout << avg << " " << std << "\n";
}
}
FreeMatrix(F_r);
FreeMatrix(F_i);
FreeMatrix(F_m);
}
code of mean and standard deviation:
double Average(Matrix* F_m, int img_height, int img_width, int scale, int orientation)
{
double avg = 0.0;
for (int h = (img_height * scale); h < (img_height * (scale + 1)); h++)
{
for (int w = (img_width * orientation); w < (img_width * (orientation + 1)); w++)
{
avg += F_m->data[h][w];
}
}
avg /= (img_height * img_width);
return avg;
}
double StandardDeviation(Matrix* F_m, int img_height, int img_width, int scale, int orientation)
{
double std = 0.0;
double avg = Average(F_m, img_height, img_width, scale, orientation);
for (int h = (img_height * scale); h < (img_height * (scale + 1)); h++)
{
for (int w = (img_width * orientation); w < (img_width * (orientation + 1)); w++)
{
double dif = F_m->data[h][w] - avg;
std += (dif * dif);
}
}
std = sqrt(std / (img_height * img_width));
return std;
}
note:
code of function of GaborFilteredImg i copied from this http://vision.ece.ucsb.edu/texture/software/gabor.c
i would like to ask if the code i wrote (starting from "Compute Texture Feature" section) is correct. I am not sure in getting mean and std given output F_r (real part) and F_i(imaginary part). Basically i calculate the mean and std for every response of gabor filter bank
===UPDATE===
Those F_r and F_i are the result of gabor filtering using scale=4 and orientation=6.
Both F_r and F_i have dimension (img_height * scale) * (img_width * orientation) basically are composed of grids for each response of gabor filter bank.
Then i compute the magnitude F_m(x,y) = sqrt(F_r(x, y) * F_r(x, y) + F_i(x, y) * F_i(x, y))
Finally i calculate the feature vector which is the mean and standard deviation of F_m
===IMAGES===
Image input (real): http://goo.gl/kc5BG
Gabor banks (real) : http://goo.gl/0qM4E
Gabor banks (imaginary) : http://goo.gl/r7Fnk
Output (real) : http://goo.gl/nxVMn
Output (imaginary) : http://goo.gl/SnD7p