stuck in use of monte-carlo integration method? - c++

I wanna use monte-carlo integration method, and my code is below. As u can see i determined the interval integration but the result is wrong ! Whats wrong with this code ?
any help will be appreciated .
#include <iostream>
#include <math.h>
#include <stdlib.h>
#define N 500
using namespace std;
double Func(double x) { return pow(x, 2) + 1; }
double Monte_Carlo(double Func(double), double xmin, double xmax, double ymin,
double ymax)
{
int acc = 0;
int tot = 0;
for (int count = 0; count < N; count++)
{
double x0 = (double)rand() / 4 + (-2);
double y0 = (double)rand() / 4 + 0;
float x = x0 / (float)RAND_MAX;
float y = y0 / (float)RAND_MAX;
cout << x << endl;
if (y <= Func(x))
acc++;
tot++;
// cout << "Dgage" << tot << '\t' << acc << endl;
}
double Coeff = acc / N;
return (xmax - xmin) * (1.2 * Func(xmax)) * Coeff;
}
int main()
{
cout << "Integral value is: " << Monte_Carlo(Func, -2, 2, 0, 4) << endl;
system("pause");
return 0;
}

The Monte_Carlo function is making things more complicated then they need to be. For integrating a 1-dimensional function, all we have to do is sample the value of the function a bunch of times within the region we're integrating over:
#include <random>
double Monte_Carlo(double Func(double), double xmin, double xmax, int N)
{
// This is the distribution we're using to generate inputs
auto x_dist = std::uniform_real_distribution<>(xmin, xmax);
// This is the random number generator itself
auto rng = std::default_random_engine();
// Calculate the total of N random samples
double total = 0.0;
for(int i = 0; i < N; i++) {
double x = x_dist(rng); // Generate a value
total += Func(x);
}
// Return the size of the interval times the total,
// divided by the number of samples
return (xmax - xmin) * total / N;
}
If we run this code with N = 1000, we get an integral value of 9.20569, which is pretty close to the exact answer (9.33333...).
// It's much more efficent to use x*x instead of pow
double func(double x) { return x * x + 1; }
int main()
{
cout << "Integral value is: " << Monte_Carlo(func, -2, 2, 1000) << endl;
getchar(); // Pause until the user presses enter
return 0;
}
We can also try multiple values of N, to have the program show how it converges. The following program calculates the integral with N being powers of 2 from 0 to 30
#include <iostream>
#include <cmath>
#include <random>
using namespace std;
double func(double x) { return x*x + 1; }
double Monte_Carlo(double Func(double), double xmin, double xmax, int N) {
auto x_dist = std::uniform_real_distribution<>(xmin, xmax);
auto rng = std::default_random_engine();
double total = 0.0;
for(int i = 0; i < N; i++) {
double x = x_dist(rng); // Generate a value
total += Func(x);
}
return (xmax - xmin) * total / N;
}
int main() {
int N = 1;
for(int i = 0; i < 31; i++) {
std::cout << "N = " << N << "\t\tintegral = " << Monte_Carlo(func, -2, 2, N) << endl;
N *= 2; // Double N
}
}
The output shows that the monte carlo method does actually converge:
N = 1 integral = 12.6889
N = 2 integral = 8.39917
N = 4 integral = 7.97521
N = 8 integral = 9.24233
N = 16 integral = 9.75632
N = 32 integral = 9.87064
N = 64 integral = 9.46945
N = 128 integral = 9.27281
N = 256 integral = 9.27395
N = 512 integral = 9.17546
N = 1024 integral = 9.19097
N = 2048 integral = 9.26203
N = 4096 integral = 9.37979
N = 8192 integral = 9.36167
N = 16384 integral = 9.28918
N = 32768 integral = 9.29766
N = 65536 integral = 9.31101
N = 131072 integral = 9.3227
N = 262144 integral = 9.32588
N = 524288 integral = 9.32805
N = 1048576 integral = 9.32726
N = 2097152 integral = 9.32722
N = 4194304 integral = 9.331
N = 8388608 integral = 9.33082
N = 16777216 integral = 9.33174
N = 33554432 integral = 9.33164
N = 67108864 integral = 9.33303
N = 134217728 integral = 9.33283
N = 268435456 integral = 9.33327
N = 536870912 integral = 9.33325
N = 1073741824 integral = 9.33333

Related

Why is this loop seeming to change the value of a variable?

The following code is meant to calculate 7 terms: tcapneg, tcappos, tneg1, tneg2, tpos1, tpos2, tzcap (only the calculation of tpos1 and tpos2 is shown here), and determine the entry that satisfies the condition of being the smallest positive non-zero entry.
int hitb;
double PCLx = 2.936728;
double PCLz = -0.016691;
double PDCx = 0.102796;
double PDCz = 0.994702;
double q = 0.002344;
double s = 0.0266;
double v = 0.0744;
double a = -q * PDCx * PDCx;
double b = s * PDCx - 2 * q*PCLx*PDCx - PDCz;
double c = -1.0*(PCLz + q * pow(PCLx, 2) - s * PCLx + v);
double d = b * b - 4 * a*c;
if (d >= 0.0f) // only take solution if t real
{
tpos1 = (-b + sqrt(d)) / (2 * a);
tpos2 = (-b - sqrt(d)) / (2 * a);
}
printf("\n %f %f %f %f %f %f %f", tcapneg, tcappos, tneg1, tneg2, tpos1, tpos2, tzcap);
yielding the result:
0.000000 0.000000 -40326.381162 -0.156221 -40105.748386 0.000194 0.016780
It is seen that the expected result should be smallest = tpos2 = 0.000194.
double smallest = -1.0;
double tlist[7] = { tcapneg, tcappos, tneg1, tneg2, tpos1, tpos2, tzcap };
const int size = sizeof(tlist) / sizeof(int);
for (int i = 0; i < size; i++)
{
if (tlist[i] > EPSILON && (smallest == -1.0 || tlist[i] < smallest))
{
smallest = tlist[i];
}
}
printf("\n %f", smallest);
The output for smallest = 0.000192, thus smallest != tpos2 != 0.00194. Why is there this small change in value for the selected smallest entry?
The result of smallest will be fed to the following code:
if (smallest == tneg1 || smallest == tneg2)
{
hitb = 1;
}
else if (smallest == tpos1 || smallest == tpos2)
{
hitb = 2;
}
else if (smallest == tcappos)
{
hitb = 3;
}
else if (smallest == tcapneg)
{
hitb = 4;
}
else if (smallest == tzcap)
{
hitb = 5;
}
In this case, we should satisfy the condition to write hitb = 2, however this is failing due to the inequality above.
Your array double tlist[7] is in double with 7 elements. sizeof(double) is 8, so sizeof(tlist) is 8*7 = 56. While sizeof(int) is 4, so your size = sizeof(tlist) / sizeof(int) is 56/4 = 14. Your loop goes beyond number of elements in the array. It counts 7 more double values after the array in memory, because the array name is used as a pointer.
Here is my code to verify the above nanalysis
#include <iostream>
using namespace std;
int main()
{
double da[7] = {0.0, 0.0, -40326.381162, -0.156221, -40105.748386, 0.000194, 0.016780};
const int sda = sizeof(da);
const int sin = sizeof(int);
const int siz = sda/sin;
cout << "sda:" << sda << " sin:" << sin << " siz:" << siz << endl;
for( int i=0; i<siz; i++ ) {
cout << "da[" << i << "] = " << da[i] << endl;
}
return 0;
}
Here is the output
sda:56 sin:4 siz:14
da[0] = 0
da[1] = 0
da[2] = -40326.4
da[3] = -0.156221
da[4] = -40105.7
da[5] = 0.000194
da[6] = 0.01678
da[7] = 2.07324e-317
da[8] = 8.48798e-314
da[9] = 1.9098e-313
da[10] = 0
da[11] = 1.31616e-312
da[12] = 0
da[13] = 6.95332e-310
The correct code is
size = sizeof(tlist) / sizeof(double);
Use the following option for GCC to report runtime error in this case
g++ -fsanitize=bounds -o main.e main.cpp
Probably you never iterate over the last elements of the array: you calculate the size as sizeof(double*) / sizeof(int) which is not true. Just use std::vector type for an array and iterate over it using iterator types:
std::vector<double>tlist = ...
for(auto i = tlist.begin(); i != tlist.end(); i++)
{
double v = (*i);
/* ... */
}
Also you should thoroughly check the logic of your condition: is EPSILON positive?

Problem with getting calculations of an array inside of an array done right

Using the formula in the pic, I need to write a program that allows the user to calculate sin(x), cos(x), tan(x). The user should enter the angle in degrees, and then the program should transform it into radians before performing the three requested calculations. For each requested calculation (i.e., sin(x), cos(x), tan(x)), I only need to calculate the first 15 terms of the series.
The problem seems to be in the arrays of the last block in the code, it keeps returning wrong results of the tan(x) series; how can I fix it?
#include <iostream>
using namespace std;
//create a function to convert angles from degrees to radian
double convertToRadian(double deg)
{ //formula : radian = (degree * pi)/180
const double pi = 3.14159265359; //declaring pi's value as a constant
return (deg * (pi / 180)); //returning the radian value
}
//create a function to calculate the exponent/power
double power(double base, unsigned int exp)
{
double result = 1;
for(int i = 0; i < exp; i++){
result = result * base;
}
return result;
}
//create a function to get the factorial of a value
double factorial(int fac)
{
if(fac > 1)
return fac * factorial(fac - 1);
else
return 1;
}
//create a function to print out arrays as we will use it to print the terms in the series
void printTerms(double terms[15])
{ for (int i = 0; i < 15; i++)
{
cout<<terms[i]<<endl;
}
}
int main()
{
double degree; //declare the variables used in the program
double valueOfCos, valueOfSin, valueOfTan; //declare variables for terms of each function
cout << "Enter angle (x) in degrees: " << endl; //prompt for user to enter angle in deg
cin >> degree;
double radian = convertToRadian(degree); //first, converting from degrees to radian
//make an array for the first 15 terms of cos(x):
double cos[15];
//make a loop to insert values in the array
for (int n = 0; n < 15; n++)
{ //type the maclaurin series formula for cos(x):
valueOfCos = (( power(-1 , n)) / (factorial(2*n))) * (power(radian, (2*n)));
cos[n] = valueOfCos;
}
//print out the first 15 terms of cos(x) in the maclaurin series:
cout << "cos(x)= ";
printTerms (cos);
//make an array for the first 15 terms of sin(x):
double sin[15];
for (int n = 0; n < 15; n++)
{
valueOfSin = ((power(-1 , n)) / (factorial((2*n + 1)))) * (power(radian, (2*n + 1)));
sin[n] = valueOfSin;
}
cout << "sin(x)= ";
printTerms (sin);
double tan[15];
for (int n = 0; n < 15; n++)
{ double bernoulli[15] = {(1/6), (-1/30),(1/42), (-1/30), (5/66), (-691/2730),
(7/6), (-3617/510), (43867/798), (-174611/330), (854513/138), (-236364091/2730),
(8553103/6),(-23749461029/870),(8615841276005/14322) };
for (int i = 0; i < 15; i++)
{
double firstNum = 0, secondNum = 0 , thirdNum = 0 , denominator = 0;
firstNum = power(-1 , n);
secondNum = power(2 , 2*n + 2);
thirdNum = ((secondNum) - 1);
denominator = factorial(2*n + 2);
valueOfTan = ((firstNum * secondNum * thirdNum * (bernoulli[i])) / denominator) *
(power(radian, 2*n + 1));
tan [n] = valueOfTan;
}
}
cout << "tan(x)= ";
printTerms (tan);
return 0;
}
This loop : for (int n = 0; n < 15; n++) is not running or entire expression. You'll need to correct something like this :
double bernoulli[15] = {(1/6), (-1/30),(1/42), (-1/30), (5/66), (-691/2730),(7/6), (-3617/510), (43867/798), (-174611/330), (854513/138), (-236364091/2730),(8553103/6),(-23749461029/870),(8615841276005/14322) };
for (int n = 0; n < 15; n++){
double firstNum = 0, secondNum = 0 , thirdNum = 0 , denominator = 0;
firstNum = power(-1 , n);
secondNum = power(2 , 2*n + 2);
thirdNum = ((secondNum) - 1);
denominator = factorial(2*n + 2);
valueOfTan = ((firstNum * secondNum * thirdNum * (bernoulli[n])) / denominator) * (power(radian, 2*n + 1));
tan [n] = valueOfTan;
}
}
You are incorrectly calculating the tan value.
In valueOfTan = ((firstNum * secondNum * thirdNum * (bernoulli[i])) / denominator) * (power(radian, 2 * n + 1));
Instead of bernoulli[i], you need to have bernoulli[2*i+2] as per the formulae.
And one more suggestion please pull the double bernoulli[15] = {(1/6), (-1/30),(1/42), (-1/30), (5/66), (-691/2730), (7/6), (-3617/510), (43867/798), (-174611/330), (854513/138), (-236364091/2730), (8553103/6),(-23749461029/870),(8615841276005/14322) array initialization out of the for loop, as it's constant you don't need to initialize it every time unnecessarily. It will increase your code runtime

Quasi-Monte Carlo Integration for inverse cumulative Normal Distribution

I am trying to integrate functions, which includes changing of variables with ICDF function (gsl_cdf_gaussian_Pinv(x[1], 1)), but the results are always wrong:
#include <fstream>
#include <iostream>
#include <memory>
#include <cmath>
#include <iomanip>
#include <ctime>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <math.h>
#include <stdio.h>
#include <gaussinv.c>
#define _USE_MATH_DEFINES
using namespace std;
double f(double[], int);
double int_mcnd(double(*)(double[], int), double[], double[], int, int);
double varr[100];
int k = 0;
double hj = 0;
double mj = 1;
# include "sobol.hpp"
int DIM_NUM = 10;
int main() {
const int n = 10; /* define how many integrals */
// const int m = 1000000; /* define how many points */
double a[n] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; /* left end-points */
double b[n] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; /* right end-points */
double result;
int i, m;
int ntimes;
cout.setf(ios::fixed | ios::showpoint);
// current time in seconds (begin calculations)
time_t seconds_i;
seconds_i = time(NULL);
m = 1; // initial number of intervals
ntimes = 20; // number of interval doublings with nmax=2^ntimes
cout << setw(12) << n << "D Integral" << endl;
for (i = 0; i <= ntimes; i = i + 1) {
result = int_mcnd(f, a, b, n, m);
cout << setw(10) << m << " " << setprecision(30) << result << endl;
m = m * 2;
}
// current time in seconds (end of calculations)
time_t seconds_f;
seconds_f = time(NULL);
cout << endl << "total elapsed time = " << seconds_f - seconds_i << " seconds" << endl << endl;
return 0;
}
double f(double x[], int n) {
double y;
int j;
y = 0.0;
/* define Multidimensional Gaussian distribution and covariance */
/* X=(x1, k=2, mu = (0, covariance matrix = (v 0 0 0
* x2 0 0 v 0 0
* x3 0 0 0 v 0
* x4) 0) 0 0 0 v) */
double v = 1;
double determinant = pow(v, 10);
double inverse = 1 / v;
double rang = gsl_cdf_gaussian_Pinv(0.99999904632568359375, 1) - gsl_cdf_gaussian_Pinv(0.00000095367431640625, 1) +
gsl_cdf_gaussian_Pinv(0.00000095367431640625, 1);
y = (1 / sqrt(pow(2 * M_PI, 10) * determinant) * exp(-0.5 * (inverse * pow(gsl_cdf_gaussian_Pinv(x[0], 1), 2) +
inverse * pow(gsl_cdf_gaussian_Pinv(x[1], 1), 2) +
inverse * pow(gsl_cdf_gaussian_Pinv(x[2], 1), 2) +
inverse * pow(gsl_cdf_gaussian_Pinv(x[3], 1), 2) +
inverse * pow(gsl_cdf_gaussian_Pinv(x[4], 1), 2) +
inverse * pow(gsl_cdf_gaussian_Pinv(x[5], 1), 2) +
inverse * pow(gsl_cdf_gaussian_Pinv(x[6], 1), 2) +
inverse * pow(gsl_cdf_gaussian_Pinv(x[7], 1), 2) +
inverse * pow(gsl_cdf_gaussian_Pinv(x[8], 1), 2) +
inverse * pow(gsl_cdf_gaussian_Pinv(x[9], 1), 2))));
return y;
}
/*==============================================================
input:
fn - a multiple argument real function (supplied by the user)
a[] - left end-points of the interval of integration
b[] - right end-points of the interval of integration
n - dimension of integral
m - number of random points
output:
r - result of integration
================================================================*/
double int_mcnd(double(*fn)(double[], int), double a[], double b[], int n, int m) {
double r, x[n], p;
int i, j;
double rarr[DIM_NUM];
long long int seed;
seed = 1;
long long int seed_in;
long long int seed_out;
srand(time(NULL)); /* initial seed value (use system time) */
r = 0.0;
p = 1.0;
// step 1: calculate the common factor p
for (j = 0; j < n; j = j + 1) {
// p = p * (b[j] - a[j]);
p=p*(gsl_cdf_gaussian_Pinv(0.99999904632568359375, 1)-gsl_cdf_gaussian_Pinv(0.00000095367431640625, 1));
}
// step 2: integration
for (i = 1; i <= m; i = i + 1) {
seed_in = seed;
i8_sobol(DIM_NUM, &seed, rarr);
seed_out = seed;
// calculate random x[] points
for (j = 0; j < n; j = j + 1) {
x[j] = a[j] + (b[j] - a[j]) * rarr[j];
}
r = r + fn(x, n);
}
cout << endl << "p = " << p << " seconds" << endl << endl;
r = r * p / m;
return r;
}
The problem is in the parametrization parameter p, which I suggest to be
p=p*(gsl_cdf_gaussian_Pinv(0.99999904632568359375, 1)-gsl_cdf_gaussian_Pinv(0.00000095367431640625, 1))
instead of standard - p = p * (b[j] - a[j]);
I want to integrate not only within [0,1]^N intervals, but also in [-20;20].
I can't define my mistake. Can somebody help, please?

Unexpected deviation from absolute value in Monte Carlo N dimensional integration in c++

I have written a code in c++ for Monte Carlo in tegration, which worked fine with my other functions when I used 2 dimensional integration. I generalized the code for N dimensional integration , in this particular case, I am taking n = 10.
I am trying to integrate a simple function f = x1+x2+x3+x4+x5+....+x10 where, x1....x10 falls within the limit [-5.0, 5.0]. I see a large deviation in the result, when I know the absolute result should be 0. I will greatly appreciate if anyone kindly takes a look at my code and figure out where my code breaks up. I am attaching the code as follows:
#include <iostream>
#include <fstream>
#include <iomanip>
#include <cmath>
#include <cstdlib>
#include <ctime>
using namespace std;
//define multivariate function F(x1, x2, ...xk)
double f(double x[], int n)
{
double y;
int j;
y = 0.0;
for (j = 0; j < n; j = j+1)
{
y = y + x[j];
}
y = y;
return y;
}
/*
* Function f(x1, x2, ... xk)
*/
//define function for Monte Carlo Multidimensional integration
double int_mcnd(double(*fn)(double[],int),double a[], double b[], int n, int m)
{
double r, x[n], p;
int i, j;
// initial seed value (use system time)
srand(time(NULL));
r = 0.0;
p = 1.0;
// step 1: calculate the common factor p
for (j = 0; j < n; j = j+1)
{
p = p*(b[j]-a[j]);
}
// step 2: integration
for (i = 1; i <= m; i=i+1)
{
// calculate random x[] points
for (j = 0; j < n; j = j+1)
{
x[j] = a[j] + static_cast <double> (rand()) /( static_cast <double> (RAND_MAX/(b[j]-a[j])));
}
r = r + fn(x,n);
}
r = r*p/m;
return r;
}
double f(double[], int);
double int_mcnd(double(*)(double[],int), double[], double[], int, int);
int main(int argc, char **argv)
{
/* define how many integrals */
const int n = 10;
double b[n] = {5.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0,5.0};
double a[n] = {-5.0, -5.0, -5.0, -5.0, -5.0, -5.0, -5.0, -5.0, -5.0,-5.0};
double result;
int i, m;
int N = 20;
cout.precision(6);
cout.setf(ios::fixed | ios::showpoint);
// current time in seconds (begin calculations)
time_t seconds_i;
seconds_i = time (NULL);
m = 2; // initial number of intervals
// convert command-line input to N = number of points
//N = atoi( argv[1] );
for (i=0; i <=N; i=i+1)
{
result = int_mcnd(f, a, b, n, m);
cout << setw(30) << m << setw(30) << result <<endl;
m = m*2;
}
// current time in seconds (end of calculations)
time_t seconds_f;
seconds_f = time (NULL);
cout << endl << "total elapsed time = " << seconds_f - seconds_i << " seconds" << endl << endl;
return 0;
}
The output I am getting is like these:
4 -41046426010.339691
8 -14557222958.913620
16 25601187040.145161
32 29498213233.367203
64 -2422980618.248888
128 -13400105151.286720
256 -11237568021.855265
512 -5950177645.396674
1024 -4726707072.013641
2048 -1240029475.829825
4096 1890210492.995555
8192 573067706.448856
16384 356227781.143659
32768 -343198855.224271
65536 171823353.999405
131072 -143383711.461758
262144 -197599063.607231
524288 -59641584.846697
1048576 10130826.266767
2097152 100880200.681037
total elapsed time = 1 seconds
which is nothing close to my expected output zero. please help me fix the code and thanks in advance.

Implementing Gaussian Blur - How to calculate convolution matrix (kernel)

My question is very close to this question: How do I gaussian blur an image without using any in-built gaussian functions?
The answer to this question is very good, but it doesn't give an example of actually calculating a real Gaussian filter kernel. The answer gives an arbitrary kernel and shows how to apply the filter using that kernel but not how to calculate a real kernel itself. I am trying to implement a Gaussian blur in C++ or Matlab from scratch, so I need to know how to calculate the kernel from scratch.
I'd appreciate it if someone could calculate a real Gaussian filter kernel using any small example image matrix.
You can create a Gaussian kernel from scratch as noted in MATLAB documentation of fspecial. Please read the Gaussian kernel creation formula in the algorithms part in that page and follow the code below. The code is to create an m-by-n matrix with sigma = 1.
m = 5; n = 5;
sigma = 1;
[h1, h2] = meshgrid(-(m-1)/2:(m-1)/2, -(n-1)/2:(n-1)/2);
hg = exp(- (h1.^2+h2.^2) / (2*sigma^2));
h = hg ./ sum(hg(:));
h =
0.0030 0.0133 0.0219 0.0133 0.0030
0.0133 0.0596 0.0983 0.0596 0.0133
0.0219 0.0983 0.1621 0.0983 0.0219
0.0133 0.0596 0.0983 0.0596 0.0133
0.0030 0.0133 0.0219 0.0133 0.0030
Observe that this can be done by the built-in fspecial as follows:
fspecial('gaussian', [m n], sigma)
ans =
0.0030 0.0133 0.0219 0.0133 0.0030
0.0133 0.0596 0.0983 0.0596 0.0133
0.0219 0.0983 0.1621 0.0983 0.0219
0.0133 0.0596 0.0983 0.0596 0.0133
0.0030 0.0133 0.0219 0.0133 0.0030
I think it is straightforward to implement this in any language you like.
EDIT: Let me also add the values of h1 and h2 for the given case, since you may be unfamiliar with meshgrid if you code in C++.
h1 =
-2 -1 0 1 2
-2 -1 0 1 2
-2 -1 0 1 2
-2 -1 0 1 2
-2 -1 0 1 2
h2 =
-2 -2 -2 -2 -2
-1 -1 -1 -1 -1
0 0 0 0 0
1 1 1 1 1
2 2 2 2 2
It's as simple as it sounds:
double sigma = 1;
int W = 5;
double kernel[W][W];
double mean = W/2;
double sum = 0.0; // For accumulating the kernel values
for (int x = 0; x < W; ++x)
for (int y = 0; y < W; ++y) {
kernel[x][y] = exp( -0.5 * (pow((x-mean)/sigma, 2.0) + pow((y-mean)/sigma,2.0)) )
/ (2 * M_PI * sigma * sigma);
// Accumulate the kernel values
sum += kernel[x][y];
}
// Normalize the kernel
for (int x = 0; x < W; ++x)
for (int y = 0; y < W; ++y)
kernel[x][y] /= sum;
To implement the gaussian blur you simply take the gaussian function and compute one value for each of the elements in your kernel.
Usually you want to assign the maximum weight to the central element in your kernel and values close to zero for the elements at the kernel borders.
This implies that the kernel should have an odd height (resp. width) to ensure that there actually is a central element.
To compute the actual kernel elements you may scale the gaussian bell to the kernel grid (choose an arbitrary e.g. sigma = 1 and an arbitrary range e.g. -2*sigma ... 2*sigma) and normalize it, s.t. the elements sum to one.
To achieve this, if you want to support arbitrary kernel sizes, you might want to adapt the sigma to the required kernel size.
Here's a C++ example:
#include <cmath>
#include <vector>
#include <iostream>
#include <iomanip>
double gaussian( double x, double mu, double sigma ) {
const double a = ( x - mu ) / sigma;
return std::exp( -0.5 * a * a );
}
typedef std::vector<double> kernel_row;
typedef std::vector<kernel_row> kernel_type;
kernel_type produce2dGaussianKernel (int kernelRadius) {
double sigma = kernelRadius/2.;
kernel_type kernel2d(2*kernelRadius+1, kernel_row(2*kernelRadius+1));
double sum = 0;
// compute values
for (int row = 0; row < kernel2d.size(); row++)
for (int col = 0; col < kernel2d[row].size(); col++) {
double x = gaussian(row, kernelRadius, sigma)
* gaussian(col, kernelRadius, sigma);
kernel2d[row][col] = x;
sum += x;
}
// normalize
for (int row = 0; row < kernel2d.size(); row++)
for (int col = 0; col < kernel2d[row].size(); col++)
kernel2d[row][col] /= sum;
return kernel2d;
}
int main() {
kernel_type kernel2d = produce2dGaussianKernel(3);
std::cout << std::setprecision(5) << std::fixed;
for (int row = 0; row < kernel2d.size(); row++) {
for (int col = 0; col < kernel2d[row].size(); col++)
std::cout << kernel2d[row][col] << ' ';
std::cout << '\n';
}
}
The output is:
$ g++ test.cc && ./a.out
0.00134 0.00408 0.00794 0.00992 0.00794 0.00408 0.00134
0.00408 0.01238 0.02412 0.03012 0.02412 0.01238 0.00408
0.00794 0.02412 0.04698 0.05867 0.04698 0.02412 0.00794
0.00992 0.03012 0.05867 0.07327 0.05867 0.03012 0.00992
0.00794 0.02412 0.04698 0.05867 0.04698 0.02412 0.00794
0.00408 0.01238 0.02412 0.03012 0.02412 0.01238 0.00408
0.00134 0.00408 0.00794 0.00992 0.00794 0.00408 0.00134
As a simplification you don't need to use a 2d-kernel. Easier to implement and also more efficient to compute is to use two orthogonal 1d-kernels. This is possible due to the associativity of this type of a linear convolution (linear separability).
You may also want to see this section of the corresponding wikipedia article.
Here's the same in Python (in the hope someone might find it useful):
from math import exp
def gaussian(x, mu, sigma):
return exp( -(((x-mu)/(sigma))**2)/2.0 )
#kernel_height, kernel_width = 7, 7
kernel_radius = 3 # for an 7x7 filter
sigma = kernel_radius/2. # for [-2*sigma, 2*sigma]
# compute the actual kernel elements
hkernel = [gaussian(x, kernel_radius, sigma) for x in range(2*kernel_radius+1)]
vkernel = [x for x in hkernel]
kernel2d = [[xh*xv for xh in hkernel] for xv in vkernel]
# normalize the kernel elements
kernelsum = sum([sum(row) for row in kernel2d])
kernel2d = [[x/kernelsum for x in row] for row in kernel2d]
for line in kernel2d:
print ["%.3f" % x for x in line]
produces the kernel:
['0.001', '0.004', '0.008', '0.010', '0.008', '0.004', '0.001']
['0.004', '0.012', '0.024', '0.030', '0.024', '0.012', '0.004']
['0.008', '0.024', '0.047', '0.059', '0.047', '0.024', '0.008']
['0.010', '0.030', '0.059', '0.073', '0.059', '0.030', '0.010']
['0.008', '0.024', '0.047', '0.059', '0.047', '0.024', '0.008']
['0.004', '0.012', '0.024', '0.030', '0.024', '0.012', '0.004']
['0.001', '0.004', '0.008', '0.010', '0.008', '0.004', '0.001']
OK, a late answer but in case of...
Using the #moooeeeep answer, but with numpy;
import numpy as np
radius = 3
sigma = radius/2.
k = np.arange(2*radius +1)
row = np.exp( -(((k - radius)/(sigma))**2)/2.)
col = row.transpose()
out = np.outer(row, col)
out = out/np.sum(out)
for line in out:
print(["%.3f" % x for x in line])
Just a bit less of lines.
Gaussian blur in python using PIL image library. For more info read this: http://blog.ivank.net/fastest-gaussian-blur.html
from PIL import Image
import math
# img = Image.open('input.jpg').convert('L')
# r = radiuss
def gauss_blur(img, r):
imgData = list(img.getdata())
bluredImg = Image.new(img.mode, img.size)
bluredImgData = list(bluredImg.getdata())
rs = int(math.ceil(r * 2.57))
for i in range(0, img.height):
for j in range(0, img.width):
val = 0
wsum = 0
for iy in range(i - rs, i + rs + 1):
for ix in range(j - rs, j + rs + 1):
x = min(img.width - 1, max(0, ix))
y = min(img.height - 1, max(0, iy))
dsq = (ix - j) * (ix - j) + (iy - i) * (iy - i)
weight = math.exp(-dsq / (2 * r * r)) / (math.pi * 2 * r * r)
val += imgData[y * img.width + x] * weight
wsum += weight
bluredImgData[i * img.width + j] = round(val / wsum)
bluredImg.putdata(bluredImgData)
return bluredImg
// my_test.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <cmath>
#include <vector>
#include <iostream>
#include <iomanip>
#include <string>
//https://stackoverflow.com/questions/8204645/implementing-gaussian-blur-how-to-calculate-convolution-matrix-kernel
//https://docs.opencv.org/2.4/modules/imgproc/doc/filtering.html#getgaussiankernel
//http://dev.theomader.com/gaussian-kernel-calculator/
double gaussian(double x, double mu, double sigma) {
const double a = (x - mu) / sigma;
return std::exp(-0.5 * a * a);
}
typedef std::vector<double> kernel_row;
typedef std::vector<kernel_row> kernel_type;
kernel_type produce2dGaussianKernel(int kernelRadius, double sigma) {
kernel_type kernel2d(2 * kernelRadius + 1, kernel_row(2 * kernelRadius + 1));
double sum = 0;
// compute values
for (int row = 0; row < kernel2d.size(); row++)
for (int col = 0; col < kernel2d[row].size(); col++) {
double x = gaussian(row, kernelRadius, sigma)
* gaussian(col, kernelRadius, sigma);
kernel2d[row][col] = x;
sum += x;
}
// normalize
for (int row = 0; row < kernel2d.size(); row++)
for (int col = 0; col < kernel2d[row].size(); col++)
kernel2d[row][col] /= sum;
return kernel2d;
}
char* gMatChar[10] = {
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" "
};
static int countSpace(float aValue)
{
int count = 0;
int value = (int)aValue;
while (value > 9)
{
count++;
value /= 10;
}
return count;
}
int main() {
while (1)
{
char str1[80]; // window size
char str2[80]; // sigma
char str3[80]; // coefficient
int space;
int i, ch;
printf("\n-----------------------------------------------------------------------------\n");
printf("Start generate Gaussian matrix\n");
printf("-----------------------------------------------------------------------------\n");
// input window size
printf("\nPlease enter window size (from 3 to 10) It should be odd (ksize/mod 2 = 1 ) and positive: Exit enter q \n");
for (i = 0; (i < 80) && ((ch = getchar()) != EOF)
&& (ch != '\n'); i++)
{
str1[i] = (char)ch;
}
// Terminate string with a null character
str1[i] = '\0';
if (str1[0] == 'q')
{
break;
}
int input1 = atoi(str1);
int window_size = input1 / 2;
printf("Input window_size was: %d\n", input1);
// input sigma
printf("Please enter sigma. Use default press Enter . Exit enter q \n");
str2[0] = '0';
for (i = 0; (i < 80) && ((ch = getchar()) != EOF)
&& (ch != '\n'); i++)
{
str2[i] = (char)ch;
}
// Terminate string with a null character
str2[i] = '\0';
if (str2[0] == 'q')
{
break;
}
float input2 = atof(str2);
float sigma;
if (input2 == 0)
{
// Open-CV sigma � Gaussian standard deviation. If it is non-positive, it is computed from ksize as sigma = 0.3*((ksize-1)*0.5 - 1) + 0.8 .
sigma = 0.3*((input1 - 1)*0.5 - 1) + 0.8;
}
else
{
sigma = input2;
}
printf("Input sigma was: %f\n", sigma);
// input Coefficient K
printf("Please enter Coefficient K. Use default press Enter . Exit enter q \n");
str3[0] = '0';
for (i = 0; (i < 80) && ((ch = getchar()) != EOF)
&& (ch != '\n'); i++)
{
str3[i] = (char)ch;
}
// Terminate string with a null character
str3[i] = '\0';
if (str3[0] == 'q')
{
break;
}
int input3 = atoi(str3);
int cK;
if (input3 == 0)
{
cK = 1;
}
else
{
cK = input3;
}
float sum_f = 0;
float temp_f;
int sum = 0;
int temp;
printf("Input Coefficient K was: %d\n", cK);
printf("\nwindow size=%d | Sigma = %f Coefficient K = %d\n\n\n", input1, sigma, cK);
kernel_type kernel2d = produce2dGaussianKernel(window_size, sigma);
std::cout << std::setprecision(input1) << std::fixed;
for (int row = 0; row < kernel2d.size(); row++) {
for (int col = 0; col < kernel2d[row].size(); col++)
{
temp_f = cK* kernel2d[row][col];
sum_f += temp_f;
space = countSpace(temp_f);
std::cout << gMatChar[space] << temp_f << ' ';
}
std::cout << '\n';
}
printf("\n Sum array = %f | delta = %f", sum_f, sum_f - cK);
// rounding
printf("\nRecommend use round(): window size=%d | Sigma = %f Coefficient K = %d\n\n\n", input1, sigma, cK);
sum = 0;
std::cout << std::setprecision(0) << std::fixed;
for (int row = 0; row < kernel2d.size(); row++) {
for (int col = 0; col < kernel2d[row].size(); col++)
{
temp = round(cK* kernel2d[row][col]);
sum += temp;
space = countSpace((float)temp);
std::cout << gMatChar[space] << temp << ' ';
}
std::cout << '\n';
}
printf("\n Sum array = %d | delta = %d", sum, sum - cK);
// recommented
sum_f = 0;
int cK_d = 1 / kernel2d[0][0];
cK_d = cK_d / 2 * 2;
printf("\nRecommend: window size=%d | Sigma = %f Coefficient K = %d\n\n\n", input1, sigma, cK_d);
std::cout << std::setprecision(input1) << std::fixed;
for (int row = 0; row < kernel2d.size(); row++) {
for (int col = 0; col < kernel2d[row].size(); col++)
{
temp_f = cK_d* kernel2d[row][col];
sum_f += temp_f;
space = countSpace(temp_f);
std::cout << gMatChar[space] << temp_f << ' ';
}
std::cout << '\n';
}
printf("\n Sum array = %f | delta = %f", sum_f, sum_f - cK_d);
// rounding
printf("\nRecommend use round(): window size=%d | Sigma = %f Coefficient K = %d\n\n\n", input1, sigma, cK_d);
sum = 0;
std::cout << std::setprecision(0) << std::fixed;
for (int row = 0; row < kernel2d.size(); row++) {
for (int col = 0; col < kernel2d[row].size(); col++)
{
temp = round(cK_d* kernel2d[row][col]);
sum += temp;
space = countSpace((float)temp);
std::cout << gMatChar[space] << temp << ' ';
}
std::cout << '\n';
}
printf("\n Sum array = %d | delta = %d", sum, sum - cK_d);
}
}
function kernel = gauss_kernel(m, n, sigma)
% Generating Gauss Kernel
x = -(m-1)/2 : (m-1)/2;
y = -(n-1)/2 : (n-1)/2;
for i = 1:m
for j = 1:n
xx(i,j) = x(i);
yy(i,j) = y(j);
end
end
kernel = exp(-(xx.*xx + yy.*yy)/(2*sigma*sigma));
% Normalize the kernel
kernel = kernel/sum(kernel(:));
% Corresponding function in MATLAB
% fspecial('gaussian', [m n], sigma)
Here's a calculation in C#, which does not take single samples from the gaussian (or another kernel) function, but it calculates a large number of samples in a small grid and integrates the samples in the desired number of sections.
The calculation is for 1D, but it may easily be extended to 2D.
This calculation uses some other functions, which I did not add here, but I have added the function signatures so that you will know what they do.
This calculation produces the following discrete values for the limits +/- 3 (sum areaSum of integral is 0.997300):
kernel size: normalized kernel values, rounded to 6 decimals
3: 0.157731, 0.684538, 0.157731
5: 0.034674, 0.238968, 0.452716, 0.238968, 0.034674
7: 0.014752, 0.083434, 0.235482, 0.332663, 0.235482, 0.083434, 0.014752
This calculation produces the following discrete values for the limits +/- 2 (sum areaSum of integral is 0.954500):
kernel size: normalized kernel values, rounded to 6 decimals
3: 0.240694, 0.518612, 0.240694
5: 0.096720, 0.240449, 0.325661, 0.240449, 0.096720
7: 0.056379, 0.124798, 0.201012, 0.235624, 0.201012, 0.124798, 0.056379
Code:
using System.Linq;
private static void Main ()
{
int positionCount = 1024; // Number of samples in the range 0..1.
double positionStepSize = 1.0 / positionCount;
double limit = 3; // The calculation range of the kernel. +/- 3 is sufficient for gaussian.
int sectionCount = 3; // The number of elements in the kernel. May be 1, 3, 5, 7, ... (n*2+1)
// calculate the x positions for each kernel value to calculate.
double[] positions = CreateSeries (-limit, positionStepSize, (int)(limit * 2 * positionCount + 1));
// calculate the gaussian function value for each position
double[] values = positions.Select (pos => Gaussian (pos)).ToArray ();
// split the values into equal-sized sections and calculate the integral of each section.
double[] areas = IntegrateInSections (values, positionStepSize, sectionCount);
double areaSum = areas.Sum ();
// normalize to 1
double[] areas1 = areas.Select (a => a / areaSum).ToArray ();
double area1Sum = areas1.Sum (); // just to check it's 1 now
}
///-------------------------------------------------------------------
/// <summary>
/// Create a series of <paramref name="i_count"/> numbers, starting at <paramref name="i_start"/> and increasing by <paramref name="i_stepSize"/>.
/// </summary>
/// <param name="i_start">The start value of the series.</param>
/// <param name="i_stepSize">The step size between values in the series.</param>
/// <param name="i_count">The number of elements in the series.</param>
///-------------------------------------------------------------------
public static double[] CreateSeries (double i_start,
double i_stepSize,
int i_count)
{ ... }
private static readonly double s_gaussian_Divisor = Math.Sqrt (Math.PI * 2.0);
/// ------------------------------------------------------------------
/// <summary>
/// Calculate the value for the given position in a Gaussian kernel.
/// </summary>
/// <param name="i_position"> The position in the kernel for which the value will be calculated. </param>
/// <param name="i_bandwidth"> The width factor of the kernel. </param>
/// <returns> The value for the given position in a Gaussian kernel. </returns>
/// ------------------------------------------------------------------
public static double Gaussian (double i_position,
double i_bandwidth = 1)
{
double position = i_position / i_bandwidth;
return Math.Pow (Math.E, -0.5 * position * position) / s_gaussian_Divisor / i_bandwidth;
}
/// ------------------------------------------------------------------
/// <summary>
/// Calculate the integrals in the given number of sections of all given values with the given distance between the values.
/// </summary>
/// <param name="i_values"> The values for which the integral will be calculated. </param>
/// <param name="i_distance"> The distance between the values. </param>
/// <param name="i_sectionCount"> The number of sections in the integration. </param>
/// ------------------------------------------------------------------
public static double[] IntegrateInSections (IReadOnlyCollection<double> i_values,
double i_distance,
int i_sectionCount)
{ ... }