Para que o Filtro de Difusão Anisotrópica fosse efetivo, foi necessário analisar diferentes combinações de , e (número de iterações). Para isso, utilizou-se uma imagem simulada de Raio-X, ou seja, com ruído gaussiano, pois a imagem simulada de Ultra-Som, como será visto adiante, não era ideal para os experimentos, e a imagem simulada de Medicina Nuclear apresentava baixa variância se comparada à de Raio-X. Inicialmente, considerou-se um número de iterações e valores de pequenos, entre 2 e 10. Isso foi necessário, pois a constante só fazia sentido se a razão fosse superior a 10. Percebeu-se que, nas regiões de borda, era superior a 50, daí a escolha de dessa ordem de grandeza. Nesse caso, nas bordas, mantendo o valor do pixel original e preservando-as, como desejado. Os resultados foram avaliados com base na relação sinal-ruído obtida, que deveria ser superior à da imagem simulada, de 12,4. As simulações foram feitas para valores de iguais a 20, 40 e 60.
Os resultados das combinações de e para estão abaixo:
Os resultados em verde indicam valores de e para os quais se obteve uma relação sinal-ruído superior a 20, preservando as bordas. Os valores em vermelho, por sua vez, indicam valores que, embora tenham relação sinal-ruído superior a 20, não preservam as bordas (pode-se notar que há um valor limite de para um mesmo , acima do qual a relação sinal-ruído volta a cair). A sigla NS indica combinações que não foram simuladas.
A seguir, refinou-se essa tabela, diminuindo a variação de e fazendo iterações. Os novos resultados encontram-se abaixo:
Percebe-se que, para mais iterações, a relação sinal-ruído aumenta. Da mesma forma, diminui-se o valor de ideal para um mesmo .
Refinando ainda mais essa tabela, agora para iterações, encontramos a maior relação sinal-ruído que pode ser obtida com os valores simulados, preservando as bordas.
A relação sinal-ruído desejada é obtida para e , conforme observado abaixo:
O código do Filtro por Difusão Anisotrópica (Filtro_Difusao_Anis.java) está anexado no final deste relatório.
Filtros para Estruturas Tubulares
O efeito speckle causa grande degradação em imagens de Ecocardiografia. É necessário um filtro que ressalte estruturas tubulares para que haja a visualização e segmentação das artérias. Uma alternativa são os filtros que usam conceitos de difusão anisotrópica, porém em direções que privilegiem os vasos.
Nesse caso, foi desenvolvido um filtro que preserva as bordas e é baseado em “máscaras”. “Máscaras” podem ser entendidas como diferentes geometrias na qual um pixel pode estar inserido. Se for feita uma análise do pixel em cada uma dessas situações, é possível detectar bordas e, assim, preservá-las.
Neste projeto, foram utilizadas 12 máscaras, cujas geometrias encontram-se abaixo, onde cada quadrado indica um pixel. Os pixels em destaque representam o pixel considerado, sob o qual será feita a filtragem.
O processo de filtragem pode, então, ser calculado de acordo com os seguintes passos:
- Cálculo da intensidade média de cada máscara
onde é o número de máscaras, é o subconjunto de pixels existente em cada máscara, é o valor do pixel e é o número de pixels em cada máscara;
-
Cálculo da variância de cada máscara em relação ao pixel considerado
- Seleção da máscara com a menor variância;
-
Substituição do valor do pixel pela intensidade média da máscara com menor variância;
- Repetição dos passos (1) a (4) para todos os pixels na imagem;
- Iteração dos passos (1) a (5) até que o valor dos pixels da imagem não mude.
O código do Filtro para Estruturas Tubulares (Filtro_Est_Tub.java) está anexado no final deste relatório.
Resultados
A seguir, têm-se as imagens resultantes da aplicação de cada um dos filtros. No caso dos Filtros de Wiener e de Lee, a janela utilizada foi de . No caso do Filtro por Difusão Anisotrópica, os parâmetros utilizados foram: , e iterações.
Imagens de Raio-X (ruído gaussiano)
Im0) Imagem simulada sem ruído Im1) Imagem simulada de RX (ruído gaussiano)
Wiener) Imagem Im1 filtrada pelo Filtro de Wiener Lee) Imagem Im1 filtrada pelo Filtro de Lee
Difusão) Imagem Im1 filtrada pelo Filtro por Difusão Anisotrópica Est) Imagem Im1 filtrada pelo Filtro para Estruturas Tubulares
Imagens de Ultra-Som (ruído speckle)
Im0) Imagem simulada sem ruído Im2) Imagem simulada de US (ruído speckle)
Wiener) Imagem Im2 filtrada pelo Filtro de Wiener Lee) Imagem Im2 filtrada pelo Filtro de Lee
Difusão) Imagem Im2 filtrada pelo Filtro por Difusão Anisotrópica Est) Imagem Im2 filtrada pelo Filtro para Estruturas Tubulares
Imagens de Medicina Nuclear (ruído Poisson)
Im0) Imagem simulada sem ruído Im2) Imagem simulada de MN (ruído Poisson)
Wiener) Imagem Im3 filtrada pelo Filtro de Wiener Lee) Imagem Im3 filtrada pelo Filtro de Lee
Difusão) Imagem Im3 filtrada pelo Filtro por Difusão Anisotrópica Est) Imagem Im3 filtrada pelo Filtro para Estruturas Tubulares
Análises
A seguir, foram feitas tabelas comparativas da aplicação de cada um dos filtros nos diversos tipos de imagens. Os filtros foram aplicados também a imagens reais de Medicina (imagens de Raio-X, Ultra-Sonografia e Medicina Nuclear). Foram calculados: média da imagem, desvio padrão da imagem e relação sinal-ruído SNR (signal-to-noise ratio). Para o cálculo da SNR, é necessário saber a variância da imagem original (sem ruído), e da imagem resultante da diferença entre a imagem ruidosa ou filtrada e a imagem sem ruído. Dessa forma, a SNR é calculada por:
A partir disso, foram feitas as tabelas a seguir.
Pode-se observar que o Filtro de Wiener possibilita o aumento da relação sinal-ruído na imagem simulada de Raio-X de 12,4 para 18,5dB e de 15,8 para 20,3dB na imagem simulada de Medicina Nuclear. O menor aumento da relação sinal-ruído aconteceu para a imagem simulada de Ultra-Som: de 2,8 para 3,3dB. Podemos assumir, assim, que ele é efetivo na filtragem de imagens com ruídos gaussianos e Poisson, conforme o esperado.
Já o Filtro de Lee se mostrou mais efetivo na filtragem de imagens com ruído speckle: o aumento da relação sinal-ruído na imagem de Ultra-Som foi o maior que ele possibilitou, de 2,8 para 4,8dB. Para o ruído gaussiano, esse aumento foi de 12,4 para 17,6dB e, para o Poisson, de 15,8 para 19,3dB. Portanto, o Filtro de Lee é bastante adequado para o tratamento de imagens com ruído speckle.
O Filtro por Difusão Anisotrópica teve um elevado desempenho na filtragem das imagens simuladas de Raio-X e Medicina Nuclear. O aumento da relação sinal-ruído foi de 12,4 para 24,2dB no caso da primeira e de 15,8 para 30,3dB no caso da segunda. Provavelmente essa relação poderia ter sido aumentada no caso do ruído Poisson, caso os valores de e tivessem sido julgados a partir da análise da imagem simulada de Medicina Nuclear. Visualmente, os resultados obtidos com o Filtro por Difusão Anisotrópica também se mostraram muito mais efetivos para esses dois tipos de ruídos, preservando as bordas e retirando o ruído das imagens.
Pode-se observar abaixo que os valores do módulo do vetor gradiente e da função foram exatamente os desejados: o módulo do gradiente foi elevado nas bordas, e a função tendeu a zero quando isso ocorreu. Portanto, as bordas foram muito bem detectadas e preservadas, conforme o esperado.
Valores do módulo do gradiente Valores da função c
No entanto, o Filtro por Difusão Anisotrópica não se mostrou efetivo na filtragem da imagem simulada de Ultra-Som: o aumento da relação sinal-ruído foi de apenas 2,8 para 3,5dB.
O Filtro para Estruturas Tubulares foi o que apresentou o menor desempenho: aumento de 12,4 para 12,7dB da relação sinal-ruído na imagem simulada de Raio-X, aumento de 2,8 para 2,9dB na imagem simulada de Ultra-Som e aumento de 15,8 para 17,3dB na imagem simulada de Medicina Nuclear. Embora esses índices sejam baixos, percebemos que sua eficiência foi maior para as imagens de Ultra-Som e Medicina Nuclear, justamente as imagens para qual esse filtro é direcionado.
Percebeu-se também que os filtros foram efetivos na filtragem de imagens reais, já que diminuíram a variância dessas imagens, mas muito menos do que nas imagens simuladas. Sendo assim, é essencial que haja uma simulação mais realista dos ruídos existentes nos diversos tipos de imagens médicas para que filtros mais eficientes possam ser desenvolvidos.
Conclusões
Das análises realizadas, percebeu-se que cada filtro foi mais eficiente justamente no tipo de imagem para o qual é destinado, exceto o Filtro por Difusão Anisotrópica. No caso desse filtro, o principal problema foi a imagem simulada de Ultra-Som utilizada, com uma variância bastante elevada ao se fazer a diferença entre ela e a imagem simulada sem ruído (da ordem de 10³, enquanto, para as outras imagens, essa variância era da ordem de 10²). Portanto, a escolha da imagem de Ultra-Som simulada comprometeu bastante o estudo.
Percebeu-se também que o ruído do tipo speckle é bastante difícil de ser simulado, principalmente por conta da natureza de seu processo de formação. A criação de imagens simuladas de Ultra-Som mais condizentes com a realidade é essencial para que filtros efetivos do efeito speckle sejam desenvolvidos.
De modo geral, todos os filtros foram efetivos, possibilitando um aumento da relação sinal-ruído da imagem e preservando as bordas, principalmente no Filtro por Difusão Anisotrópica. Essa característica de preservação é essencial no processo de quantificação de estruturas das imagens, já que ele é precedido pela segmentação, que é pouco eficiente em imagens ruidosas.
Referências Bibliográficas
-
FURUIE, S.S; MASCARENHAS, N.D.A. "Tomographic reconstruction of images with Poisson noise: projection estimation". Automedica,15(2):133-40,1992.ISSN 0095-0963
-
YU Y, ACTON ST – Speckle Reducing Anisotropic Diffusion – IEEE Transactions on Image Processing, Vol. 11, No. 11, Nov. 2002: pp. 1260 – 1270;
-
LOIZOU CP et al. – Comparative Evaluation of Despeckle Filtering In Ultrasound Imaging of the Carotid Artery – IEEE Transactions on Ultrasonics, Ferroelectrics and Frequency Control 2005; vol. 52; No. 10; pp. 1653 – 1669;
-
CHITWONG S, CHEEVAVUSIT F, DEJHAN K, MITATHA S, NOKYOO C, PAUNGMA T - Segmentation on Edge Preserving Smoothing Image based on Graph Theory – IEEE, 2000: pp. 621-623.
Anexos
Filtro_Wiener.java
import ij.*;
import ij.gui.*;
public class Filtro_Wiener {
public Filtro_Wiener() {
ImagePlus imp = WindowManager.getCurrentImage();
if (imp == null) {
IJ.showMessage("Sem nada.");
return;
}
if (imp.getType() != ImagePlus.GRAY8 && imp.getType() != ImagePlus.GRAY16 && imp.getType() != ImagePlus.GRAY32) {
IJ.showMessage("Apenas processa imagens 8-bit, 16-bit ou 32-bit.");
return;
}
GenericDialog gd = new GenericDialog("Tamanho da janela");
gd.addNumericField("N", 5, 0);
gd.showDialog();
if (gd.wasCanceled())
return;
int N = (int)gd.getNextNumber();
IJ.showMessage("N=" + N);
ImageAccess input = new ImageAccess(imp.getProcessor());
ImageAccess output = this.filtro (input, N);
output.show("janela " + N + " x " + N + imp.getTitle());
}
public ImageAccess filtro(ImageAccess in, int N) {
int nx = in.getWidth();
int ny = in.getHeight();
ImageAccess out = new ImageAccess(nx, ny);
IJ.showMessage("nx=" + nx + "ny=" + ny);
double temp, media, var, anterior=0, varmax;
// Cálculo da variância máxima.
for (int i=0; i<nx; i++) {
for (int j=0; j<ny; j++) {
temp=0;
for (int I=i-N/2; I<=i+N/2; I++) {
for (int J=j-N/2; J<=j+N/2; J++) {
temp +=in.getPixel(I, J);
}
}
media=temp/(N*N); // Cálculo da média local, utilizado para variância máxima.
temp=0;
for (int I=i-N/2; I<=i+N/2; I++) {
for (int J=j-N/2; J<=j+N/2; J++) {
temp += (in.getPixel(I, J) - media)*(in.getPixel(I, J) - media);
}
}
var=temp/N;
if (var>anterior) anterior=var;
}
}
varmax=anterior;
double beta, novo;
// Cálculo da variância local e do novo valor do pixel.
for (int i=0; i<nx; i++) {
for (int j=0; j<ny; j++) {
temp=0;
for (int I=i-N/2; I<=i+N/2; I++) {
for (int J=j-N/2; J<=j+N/2; J++) {
temp +=in.getPixel(I, J);
}
}
media=temp/(N*N); // Cálculo da média local.
temp=0;
for (int I=i-N/2; I<=i+N/2; I++) {
for (int J=j-N/2; J<=j+N/2; J++) {
temp += (in.getPixel(I, J) - media)*(in.getPixel(I, J) - media);
}
}
var=temp/N; // Cálculo da variância local.
beta=var/varmax; // Cálculo de beta.
novo=beta*in.getPixel(i, j)+(1-beta)*media; // Cálculo do novo valor do pixel.
out.putPixel(i, j, novo);
}
}
return out;
}
}
Filtro_Lee.java
import java.awt.Rectangle;
import ij.*;
import ij.process.*;
import ij.gui.*;
public class Filtro_Lee {
public Filtro_Lee() {
ImagePlus imp = WindowManager.getCurrentImage();
if (imp == null) {
IJ.showMessage("Sem nada.");
return;
}
if (imp.getType() != ImagePlus.GRAY8 && imp.getType() != ImagePlus.GRAY16 && imp.getType() != ImagePlus.GRAY32) {
IJ.showMessage("Apenas processa imagens 8-bit, 16-bit ou 32-bit.");
return;
}
GenericDialog gd = new GenericDialog("Tamanho da janela");
gd.addNumericField("N", 5, 0);
gd.showDialog();
if (gd.wasCanceled())
return;
int N = (int)gd.getNextNumber();
// Usuário deve escolher uma região retangular.
ImageProcessor ip = imp.getProcessor();
Rectangle roi = ip.getRoi();
int rx = (int)roi.getX();
int ry = (int)roi.getY();
int w = (int)roi.getWidth();
int h = (int)roi.getHeight();
IJ.showMessage("rx = " + rx + "ry = " + ry);
ImageAccess input = new ImageAccess(imp.getProcessor());
ImageAccess output = this.filtro(imp,input, N, rx, ry, w, h);
output.show("janela " + N + " x " + N + imp.getTitle());
}
public ImageAccess filtro(ImagePlus imp, ImageAccess in, int N, int rx, int ry, int w, int h) {
int nx = in.getWidth();
int ny = in.getHeight();
ImageAccess out = new ImageAccess(nx, ny);
double temp=0, media, var, Cu2;
// Cálculos do ruído, que é o mesmo para toda a imagem, e de Cu2.
for (int I=ry; I<ry+h; I++) {
for (int J=rx; J<rx+w; J++) {
temp +=in.getPixel(J,I);
}
}
media=temp/(h*w); // Cálculo da média do ruído.
temp=0;
for (int I=ry; I<ry+h; I++) {
for (int J=rx; J<rx+w; J++) {
temp += (in.getPixel(J,I) - media)*(in.getPixel(J,I) - media);
}
}
var=temp/(h*w); // Cálculo da variância do ruído.
Cu2 = var/(media*media); // Cálculo de Cu2.
double novo, Cs2, ks;
// Calcula o novo valor do pixel.
for (int i=0; i<nx; i++) {
for (int j=0; j<ny; j++) {
temp=0;
for (int I=i-N/2; I<=i+N/2; I++) {
for (int J=j-N/2; J<=j+N/2; J++) {
temp +=in.getPixel(I, J);
}
}
media=temp/(N*N); // Cálculo da média local.
temp=0;
for (int I=i-N/2; I<=i+N/2; I++) {
for (int J=j-N/2; J<=j+N/2; J++) {
temp += (in.getPixel(I, J) - media)*(in.getPixel(I, J) - media);
}
}
var=temp/N; // Cálculo da variância local.
Cs2 = var/(media*media); // Cálculo de Cs2.
ks = 1-Cu2/Cs2; // Cálculo do fator de peso ks.
if (ks<0) ks=0;
if (ks>1) ks=1;
novo=media+ks*(in.getPixel(i, j)-media); // Cálculo do novo valor do pixel.
out.putPixel(i, j, novo);
}
}
return out;
}
}
Filtro_Difusao_Anis.java
import ij.*;
import ij.gui.*;
public class Filtro_Difusao_Anis {
public Filtro_Difusao_Anis() {
ImagePlus imp = WindowManager.getCurrentImage();
if (imp == null) {
IJ.showMessage("Sem nada.");
return;
}
if (imp.getType() != ImagePlus.GRAY8 && imp.getType() != ImagePlus.GRAY16 && imp.getType() != ImagePlus.GRAY32) {
IJ.showMessage("Apenas processa imagens 8-bit, 16-bit ou 32-bit.");
return;
}
GenericDialog gd = new GenericDialog("Valor de K, inteiro.");
gd.addNumericField("K", 3, 0);
gd.showDialog();
if (gd.wasCanceled())
return;
int K = (int)gd.getNextNumber();
GenericDialog gd2 = new GenericDialog("Valor de N, número de iterações, inteiro.");
gd2.addNumericField("N", 60, 0);
gd2.showDialog();
if (gd2.wasCanceled())
return;
int N = (int)gd2.getNextNumber();
GenericDialog gd3 = new GenericDialog("Valor de lambda, entre 0 e 1.");
gd3.addNumericField("lambda", 0.7, 0);
gd3.showDialog();
if (gd3.wasCanceled())
return;
double lambda = (double)gd3.getNextNumber();
ImageAccess input = new ImageAccess(imp.getProcessor());
ImageAccess output = this.filtro(imp,input,K,N,lambda);
output.show("Resultado" + imp.getTitle());
}
public ImageAccess filtro(ImagePlus imp, ImageAccess in, int K, int N, double lambda) {
int nx = in.getWidth();
int ny = in.getHeight();
ImageAccess out = new ImageAccess(nx, ny);
ImageAccess C = new ImageAccess(nx, ny);
for (int n=1; n<=N; n++){
// Cálculo da função c(mgrad).
double c;
for (int i=0; i<nx; i++) {
for (int j=0; j<ny; j++) {
c = 1/(1+(Math.pow(in.getPixel(i+1,j)-in.getPixel(i-1,j),2)+Math.pow(in.getPixel(i,j+1)-in.getPixel(i,j-1),2))/(4*K*K)); //4 ou 2?
C.putPixel(i, j, c);
}
}
for (int i=0; i<nx; i++) {
for (int j=0; j<ny; j++) {
// Cálculo do novo valor do pixel.
double novo,p1,p2,p3,p4,der;
p1 = C.getPixel(i+1, j)*(in.getPixel(i+2, j) - in.getPixel(i, j));
p2 = C.getPixel(i-1, j)*(in.getPixel(i-2, j) - in.getPixel(i, j));
p3 = C.getPixel(i, j+1)*(in.getPixel(i, j+2) - in.getPixel(i, j));
p4 = C.getPixel(i, j-1)*(in.getPixel(i, j-2) - in.getPixel(i, j));
der = p1+p2+p3+p4;
novo = in.getPixel(i,j) + (lambda/4.0)*der;
out.putPixel(i,j,novo);
}
}
in = out;
}
return out;
}
}
Filtro_Est_Tub.java
import ij.*;
public class Filtro_Est_Tub {
public Filtro_Est_Tub() {
ImagePlus imp = WindowManager.getCurrentImage();
if (imp == null) {
IJ.showMessage("Sem nada.");
return;
}
if (imp.getType() != ImagePlus.GRAY8 && imp.getType() != ImagePlus.GRAY16 && imp.getType() != ImagePlus.GRAY32) {
IJ.showMessage("Apenas processa imagens 8-bit, 16-bit ou 32-bit.");
return;
}
ImageAccess input = new ImageAccess(imp.getProcessor());
ImageAccess output = this.filtro(imp,input);
output.show("Resultado" + imp.getTitle());
}
public ImageAccess filtro(ImagePlus imp, ImageAccess in) {
int nx = in.getWidth();
int ny = in.getHeight();
ImageAccess out = new ImageAccess(nx, ny);
double m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12;
double v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, vp;
int cont=0;
while (in != out) {
if (cont != 0) in=out; // Pois a primeira imagem deve ser a original.
for (int i=0; i<nx; i++){
for (int j=0; j<ny; j++) {
double vmin=1000.0;
vp = in.getPixel(i,j);
// Máscara 1: Vertical.
v1 = (Math.pow(in.getPixel(i-2, j)-vp, 2)+Math.pow(in.getPixel(i-1, j)-vp, 2)+Math.pow(in.getPixel(i+1, j)-vp, 2)+Math.pow(in.getPixel(i+2, j)-vp, 2))/5;
if (v1<vmin) {
vmin=v1;
m1 = (in.getPixel(i-2, j)+in.getPixel(i-1,j)+vp+in.getPixel(i+1,j)+in.getPixel(i+2,j))/5;
out.putPixel(i,j,m1);
}
// Máscara 2: Horizontal.
v2 = (Math.pow(in.getPixel(i, j-2)-vp, 2)+Math.pow(in.getPixel(i, j-1)-vp, 2)+Math.pow(in.getPixel(i, j+1)-vp, 2)+Math.pow(in.getPixel(i, j+2)-vp, 2))/5;
if (v2<vmin) {
vmin=v2;
m2 = (in.getPixel(i, j-2)+in.getPixel(i,j-1)+vp+in.getPixel(i,j+1)+in.getPixel(i,j+2))/5;
out.putPixel(i,j,m2);
}
// Máscara 3: Diagonal \.
v3 = (Math.pow(in.getPixel(i-2, j-2)-vp, 2)+Math.pow(in.getPixel(i-1, j-1)-vp, 2)+Math.pow(in.getPixel(i+1, j+1)-vp, 2)+Math.pow(in.getPixel(i+2, j+2)-vp, 2))/5;
if (v3<vmin) {
vmin=v3;
m3 = (in.getPixel(i-2, j-2)+in.getPixel(i-1,j-1)+vp+in.getPixel(i+1,j+1)+in.getPixel(i+2,j+2))/5;
out.putPixel(i,j,m3);
}
// Máscara 4: Diagonal /.
v4 = (Math.pow(in.getPixel(i-2, j+2)-vp, 2)+Math.pow(in.getPixel(i-1, j+1)-vp, 2)+Math.pow(in.getPixel(i+1, j-1)-vp, 2)+Math.pow(in.getPixel(i+2, j-2)-vp, 2))/5;
if (v4<vmin) {
vmin=v4;
m4 = (in.getPixel(i-2, j+2)+in.getPixel(i-1,j+1)+vp+in.getPixel(i+1,j-1)+in.getPixel(i+2,j-2))/5;
out.putPixel(i,j,m4);
}
// Máscara 5: 3 debaixo + superior esquerdo.
v5 = (Math.pow(in.getPixel(i-1, j-1)-vp, 2)+Math.pow(in.getPixel(i+1, j-1)-vp, 2)+Math.pow(in.getPixel(i+1, j)-vp, 2)+Math.pow(in.getPixel(i+1, j+1)-vp, 2))/5;
if (v5<vmin) {
vmin=v5;
m5= (in.getPixel(i-1, j-1)+vp+in.getPixel(i+1,j-1)+in.getPixel(i+1,j)+in.getPixel(i+1,j+1))/5;
out.putPixel(i,j,m5);
}
// Máscara 6: 3 debaixo + superior direito.
v6 = (Math.pow(in.getPixel(i-1, j+1)-vp, 2)+Math.pow(in.getPixel(i+1, j-1)-vp, 2)+Math.pow(in.getPixel(i+1, j)-vp, 2)+Math.pow(in.getPixel(i+1, j+1)-vp, 2))/5;
if (v6<vmin) {
vmin=v6;
m6 = (in.getPixel(i-1, j+1)+vp+in.getPixel(i+1,j-1)+in.getPixel(i+1,j)+in.getPixel(i+1,j+1))/5;
out.putPixel(i,j,m6);
}
// Máscara 7: 3 de cima + inferior esquerdo.
v7 = (Math.pow(in.getPixel(i-1, j-1)-vp, 2)+Math.pow(in.getPixel(i-1, j)-vp, 2)+Math.pow(in.getPixel(i-1, j+1)-vp, 2)+Math.pow(in.getPixel(i+1, j-1)-vp, 2))/5;
if (v7<vmin) {
vmin=v7;
m7 = (in.getPixel(i-1, j-1)+in.getPixel(i-1,j)+in.getPixel(i-1,j+1)+vp+in.getPixel(i+1,j-1))/5;
out.putPixel(i,j,m7);
}
// Máscara 8: 3 de cima + inferior direito.
v8 = (Math.pow(in.getPixel(i-1, j-1)-vp, 2)+Math.pow(in.getPixel(i-1, j)-vp, 2)+Math.pow(in.getPixel(i-1, j+1)-vp, 2)+Math.pow(in.getPixel(i+1, j+1)-vp, 2))/5;
if (v8<vmin) {
vmin=v8;
m8 = (in.getPixel(i-1, j-1)+in.getPixel(i-1,j)+in.getPixel(i-1,j+1)+vp+in.getPixel(i+1,j+1))/5;
out.putPixel(i,j,m8);
}
// Máscara 9: V para esquerda.
v9 = (Math.pow(in.getPixel(i-2, j-2)-vp, 2)+Math.pow(in.getPixel(i-1, j-1)-vp, 2)+Math.pow(in.getPixel(i+1, j-1)-vp, 2)+Math.pow(in.getPixel(i+2, j-2)-vp, 2))/5;
if (v9<vmin) {
vmin=v9;
m9 = (in.getPixel(i-2, j-2)+in.getPixel(i-1,j-1)+vp+in.getPixel(i+1,j-1)+in.getPixel(i+2,j-2))/5;
out.putPixel(i,j,m9);
}
// Máscara 10: 3 V para cima.
v10 = (Math.pow(in.getPixel(i-2, j-2)-vp, 2)+Math.pow(in.getPixel(i-1, j-1)-vp, 2)+Math.pow(in.getPixel(i-1, j+1)-vp, 2)+Math.pow(in.getPixel(i-2, j+2)-vp, 2))/5;
if (v10<vmin) {
vmin=v10;
m10 = (in.getPixel(i-2, j-2)+in.getPixel(i-1,j-1)+vp+in.getPixel(i-1,j+1)+in.getPixel(i-2,j+2))/5;
out.putPixel(i,j,m10);
}
// Máscara 11: V para direita.
v11 = (Math.pow(in.getPixel(i-2, j+2)-vp, 2)+Math.pow(in.getPixel(i-1, j+1)-vp, 2)+Math.pow(in.getPixel(i+1, j+1)-vp, 2)+Math.pow(in.getPixel(i+2, j+2)-vp, 2))/5;
if (v11<vmin) {
vmin=v11;
m11 = (in.getPixel(i-2, j+2)+in.getPixel(i-1,j+1)+vp+in.getPixel(i+1,j+1)+in.getPixel(i+2,j+2))/5;
out.putPixel(i,j,m11);
}
// Máscara 12: V para baixo.
v12 = (Math.pow(in.getPixel(i+2, j-2)-vp, 2)+Math.pow(in.getPixel(i+1, j-1)-vp, 2)+Math.pow(in.getPixel(i+1, j+1)-vp, 2)+Math.pow(in.getPixel(i+2, j+2)-vp, 2))/5;
if (v12<vmin) {
vmin=v12;
m12 = (in.getPixel(i+2, j-2)+in.getPixel(i+1,j-1)+vp+in.getPixel(i+1,j+1)+in.getPixel(i+2,j+2))/5;
out.putPixel(i,j,m12);
}
}
}
cont++;
}
return out;
}
}