Construir uma matriz gaussiana

12

O desfoque gaussiano é um método usado para desfocar as imagens sem problemas. Envolve a criação de uma matriz que será usada pela convolução com os pixels de uma imagem. Nesse desafio, sua tarefa é construir essa matriz usada no desfoque gaussiano. Irá levar uma entrada r que será o raio do borrão e uma entrada σ que será o desvio padrão, a fim de construir uma matriz com dimensões (2 r + 1 × 2 r + 1). Cada valor nessa matriz terá um valor ( x , y ) que depende de sua distância absoluta em cada direção do centro e será usado para calcular G ( x , y ) onde a fórmulaG é

Fórmula

Por exemplo, se r = 2, queremos gerar uma matriz 5 x 5. Primeiro, a matriz de valores ( x , y ) é

(2, 2) (1, 2) (0, 2) (1, 2) (2, 2)
(2, 1) (1, 1) (0, 1) (1, 1) (2, 1)
(2, 0) (1, 0) (0, 0) (1, 0) (2, 0)
(2, 1) (1, 1) (0, 1) (1, 1) (2, 1)
(2, 2) (1, 2) (0, 2) (1, 2) (2, 2)

Então, deixe σ = 1,5 e aplique G a cada ( x , y )

0.0119552 0.0232856 0.0290802 0.0232856 0.0119552
0.0232856 0.0453542 0.0566406 0.0453542 0.0232856
0.0290802 0.0566406 0.0707355 0.0566406 0.0290802
0.0232856 0.0453542 0.0566406 0.0453542 0.0232856
0.0119552 0.0232856 0.0290802 0.0232856 0.0119552

Normalmente no desfoque de imagem, essa matriz seria normalizada pegando a soma de todos os valores nessa matriz e dividindo por ela. Para esse desafio, isso não é necessário e os valores brutos calculados pela fórmula são os que devem ser os resultados.

Regras

  • Isso é então o código mais curto vence.
  • A entrada r será um número inteiro não negativo e σ será um número real positivo.
  • A saída deve representar uma matriz. Ele pode ser formatado como uma matriz 2D, uma string representando uma matriz 2D ou algo semelhante.
  • Imprecisões de ponto flutuante não serão contadas contra você.

Casos de teste

(r, σ) = (0, 0.25)
2.54648

(1, 7)
0.00318244 0.00321509 0.00318244
0.00321509 0.00324806 0.00321509
0.00318244 0.00321509 0.00318244

(3, 2.5)
0.00603332 0.00900065 0.0114421  0.012395 0.0114421 0.00900065 0.00603332
0.00900065  0.0134274 0.0170696 0.0184912 0.0170696  0.0134274 0.00900065
 0.0114421  0.0170696 0.0216997  0.023507 0.0216997  0.0170696  0.0114421
  0.012395  0.0184912  0.023507 0.0254648  0.023507  0.0184912   0.012395
 0.0114421  0.0170696 0.0216997  0.023507 0.0216997  0.0170696  0.0114421
0.00900065  0.0134274 0.0170696 0.0184912 0.0170696  0.0134274 0.00900065
0.00603332 0.00900065 0.0114421  0.012395 0.0114421 0.00900065 0.00603332

(4, 3.33)
0.00339074 0.00464913 0.00582484 0.00666854 0.00697611 0.00666854 0.00582484 0.00464913 0.00339074
0.00464913 0.00637454 0.00798657  0.0091434 0.00956511  0.0091434 0.00798657 0.00637454 0.00464913
0.00582484 0.00798657  0.0100063  0.0114556   0.011984  0.0114556  0.0100063 0.00798657 0.00582484
0.00666854  0.0091434  0.0114556   0.013115  0.0137198   0.013115  0.0114556  0.0091434 0.00666854
0.00697611 0.00956511   0.011984  0.0137198  0.0143526  0.0137198   0.011984 0.00956511 0.00697611
0.00666854  0.0091434  0.0114556   0.013115  0.0137198   0.013115  0.0114556  0.0091434 0.00666854
0.00582484 0.00798657  0.0100063  0.0114556   0.011984  0.0114556  0.0100063 0.00798657 0.00582484
0.00464913 0.00637454 0.00798657  0.0091434 0.00956511  0.0091434 0.00798657 0.00637454 0.00464913
0.00339074 0.00464913 0.00582484 0.00666854 0.00697611 0.00666854 0.00582484 0.00464913 0.00339074
milhas
fonte
Qual é a precisão de que precisamos de pi e e?
Xnor
@xnor Boa pergunta. Se o seu idioma permitir, você pode assumir que esses valores já estão armazenados em uma variável ou algo semelhante. Caso contrário, você pode usar valores com duas casas decimais, produzindo pi = 3,14 e e = 2,72, onde é possível contar cada um desses valores como um único byte. Obviamente, imprecisões na resposta final não serão contadas novamente contra você.
milhas
A saída precisa ser um número decimal ou pode ser um número exato com constantes?
JungHwan Min
@JungHwanMin Os números exatos, como os do Mathematica, são bons.
miles
1
@ milhas Eu acho que seria mais fácil se você apenas exigisse uma certa precisão (por exemplo, 3 casas decimais).
orlp

Respostas:

7

Mathematica, 60 54 50 bytes

Obrigado @GregMartin por 4 bytes!

Array[s=2#2^2;E^(-{##}.{##}/s)/π/s&,1+2{#,#},-#]&

Pega re sigma como entrada, retorna a matriz (números exatos).

Versão embutida (58 bytes)

GaussianMatrix[{##},Standardized->1<0,Method->"Gaussian"]&

Obviamente, o Mathematica também tem um built-in para isso, mas é muito longo.

JungHwan Min
fonte
4
Você pode substituir -lpor -#no final ( Arrayenfiará isso nas duas dimensões para você); isso elimina a necessidade de definir l, economizando 4 bytes.
Greg Martin
5

MATL , 20 bytes

_G&:U&+iUE/_Ze5MYP*/

Experimente online!

Explicação

_     % Take input r implicitly. Negate
G     % Push r again
&:    % Binary range: [-r -r+1 ... r]
U     % Square, elementwise
&+    % Matrix of all pairwise additions
i     % Take input σ
U     % Square
E     % Multiply by 2. Gives 2σ^2
/     % Divide
_     % Negate
Ze    % Exponential
5M    % Push 2σ^2 again
YP    % Push pi
*     % Multiply
/     % Divide. Display implicitly
Luis Mendo
fonte
5

Oitava, 45 bytes

@(r,s)exp((x=-(-r:r).^2/2/s^2)+x')/2/s^2/pi
Rainer P.
fonte
4

Oitava, 49 bytes

@(r,q)1./((Q=2*q^2)*pi*e.^(((x=(-r:r).^2)+x')/Q))

Experimente Online!

rahnema1
fonte
4

Python, 88 bytes

lambda r,s:[[.5/3.14/s/s/2.72**((x*x+y*y)/2/s/s)for x in range(-r,r+1)]for y in range(-r,r+1)]

Usa a regra na qual você pode codificar 3.14 e 2.72 a um custo de 1 byte cada.

orlp
fonte
1

Perl 6 , 71 bytes

->\r,\σ{map ->\y{map ->\x{exp((x*x+y*y)/-2/σ/σ)/2/pi/σ/σ},-r..r},-r..r}

Tecnicamente, isso pode ter mais de 71 bytes se codificado e salvo em um arquivo, mas não resisti em nomear a entrada "sigma" com um sigma grego real. Ele poderia ser renomeado para qualquer carta ASCII comum, se alguém quisesse.

Sean
fonte
1

Linguagem de Macro SAS, 296 bytes

Provavelmente uma maneira muito mais eficiente de fazer isso, mas funciona :)

Este código imprime o conjunto de dados resultante.

%macro G(r,s);%let l=%eval(2*&r+1);%let pi=%sysfunc(constant(pi));data w;array a[*] t1-t&l;%do i=-&r %to &r;%do j=-&r %to &r;%let t=%sysfunc(sum(&j,&r,1));a[&t]=%sysevalf(1/(2*&pi*&s**2)*%sysfunc(exp(-(%sysfunc(abs(&j))**2+%sysfunc(abs(&i))**2)/(2*&s**2))));%end;output;%end;proc print;run;%mend;
J_Lard
fonte
1

Haskell, 59 bytes

r#s|i<-[-r..r]=[[exp(-(x*x+y*y)/2/s/s)/2/pi/s/s|x<-i]|y<-i]

Exemplo de uso:

1#7

[[3.1824449424224664e-3,3.2150851187016326e-3,3.1824449424224664e-3],
 [3.2150851187016326e-3,3.2480600630999047e-3,3.2150851187016326e-3],
 [3.1824449424224664e-3,3.2150851187016326e-3,3.1824449424224664e-3]]
nimi
fonte
0

Python 2.7, 167 bytes

Uma solução muito simples:

from __future__ import division;from math import*;r,s=input();s*=2*s;R=range(-r,r+1);print"\n".join("\t".join(str(pow(e,-(x*x+y*y)/s)/(pi*s))[:9]for x in R)for y in R)

Experimente aqui !

Ungolfed:

from __future__ import division
from math import *
r,s = input()                         # Take input
s *= 2*s                              # Set s = 2*s^2; simplifies the expression
R = range(-r,r+1)                     # Range object; used twice

                                   # G(x,y)             # Stripped
print "\n".join("\t".join(str(pow(e,-(x*x + y*y)/s)/(pi*s))[:9] for x in R) for y in R)
Calconym
fonte
5
from __future__ import division, realmente?
orlp