Per l'attuazione del gaussian blur è sufficiente prendere il gaussian function e calcolare un valore per ciascuno degli elementi nel vostro kernel.
In genere si desidera assegnare il peso massimo all'elemento centrale nel kernel e valori prossimi allo zero per gli elementi ai bordi del kernel. Ciò implica che il kernel dovrebbe avere un'altezza dispari (larghezza) per garantire che ci sia effettivamente un elemento centrale.
Per calcolare gli elementi effettivi kernel si può scalare la campana gaussiana alla rete kernel (scegliere un arbitrario esempio sigma = 1
e un intervallo arbitrario esempio -2*sigma ... 2*sigma
) e normalizzare esso, S.T. gli elementi sommano a uno. Per raggiungere questo obiettivo, se si desidera supportare dimensioni del kernel arbitrarie, è possibile adattare il sigma alla dimensione del kernel richiesta.
Ecco un esempio C++:
#include <cmath>
#include <vector>
#include <iostream>
#include <iomanip>
double gaussian (double x, double mu, double sigma) {
return std::exp(-(((x-mu)/(sigma))*((x-mu)/(sigma)))/2.0);
}
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';
}
}
L'output è:
$ g++ test.cc && ./a.out
0.00134 0.00408 0.00794 0.00992 0.00794 0.00408 0.00134
0.00408 0..02412 0.03012 0.02412 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..02412 0.03012 0.02412 0..00408
0.00134 0.00408 0.00794 0.00992 0.00794 0.00408 0.00134
Come una semplificazione non è necessario utilizzare un 2d-kernel. Più semplice da implementare e anche più efficiente da calcolare è utilizzare due kernel 1d ortogonali. Ciò è possibile a causa dell'associatività di questo tipo di convoluzione lineare (separabilità lineare). Si potrebbe anche voler vedere this section del corrispondente articolo di Wikipedia.
Ecco lo stesso in Python (con la speranza che qualcuno potrebbe trovare utile):
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]
produce il 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']
Avere leggete questo: http://en.wikipedia.org/wiki/Gaussian_function? –
O anche questo: http://en.wikipedia.org/wiki/Gaussian_blur – Bart
Sì, ho passato un sacco di tempo a cercare di capirli. Quello di cui ho bisogno è un esempio graduale. Dopo averlo capito, probabilmente aggiungerò l'esempio alla pagina Sfocatura gaussiana. – gsingh2011