/*+-------------------------------------------------------------------------+
  | MORFOLOGIA MATEMATICA:                                                  |
  | ----------------------                                                  |
  |                                                                         |
  | MORFO.H                                                                 |
  |                                                                         |
  |       Arquivo que contem as rotinas para algumas operacoes morfologicas |
  | basicas como: DILATACAO, EROSAO, GRADIENTE.                             |
  |                                                                         |
  +-------------------------------------------------------------------------+*/

/*+-------------------------------------------------------------------------+
  | Implementacao da DILATACAO numerica:                                    |
  |    A dilatacao numerica para um elemento estruturante plano, e' simples-|
  | mente atribuir para cada pixel o valor maximo da sua vizinhanca conside-|
  | rada. Neste caso estamos considerando os 8-vizinhos de um ponto.        |
  | PARAMETROS:                                                             |
  |   I   = ponteiro para imagem (entra)                                    |
  |   O   = ponteiro da imagem resultado (retorna)                          |
  |   nl  = numero de linhas da imagem                                      |
  |   nc  = numero de colunas da imagem                                     |
  +-------------------------------------------------------------------------+*/
void dilata (int *I, int *O, int nl, int nc) {
  int i, j, di, dj, max;
  for (i = 0; i < nl; i++)
     for (j = 0; j < nc; j++) {
	 if (i == 0 || i == nl - 1 || j == 0 || j == nc - 1)
	     *(O+i*nc+j) = *(I+i*nc+j);
	 else {
	     max = 0;
	     for (di = -1; di != 2; di++)
		 for (dj = -1; dj != 2; dj++)
		     if (*(I+(i+di)*nc + j+dj) > max)
			 max = *(I+(i+di)*nc+j+dj);
	     *(O+i*nc+j) = max;
	 } 
     }
}

/*+-------------------------------------------------------------------------+
  | Implementacao da EROSAO numerica:                                       |
  |    A erosao numerica para um elemento estruturante plano e' simplesmente|
  | atribuir para cada pixel o valor minimo da sua vizinhanca considerada.  |
  | PARAMETROS:                                                             |
  |   I   = ponteiro da imagem (entra)                                      |
  |   O   = ponteiro da imagem resultado (saida)                            |
  |   nl  = numero de linhas da imagem                                      |
  |   nc  = numero de colunas da imagem                                     |
  |   mn  = maximo nivel de cinza                                           |
  +-------------------------------------------------------------------------+*/
void erode (int *I, int *O, int nl, int nc, int mn) {
  int i, j, di, dj, min;
  for (i = 0; i < nl; i++)
     for (j = 0; j < nc; j++) {
	 if (i == 0 || i == nl - 1 || j == 0 || j == nc - 1)
	     *(O+i*nc+j) = *(I+i*nc+j);
	 else {
	     min = mn;
	     for (di = -1; di != 2; di++)
		 for (dj = -1; dj != 2; dj++)
		     if (*(I+(i+di)*nc + j+dj) < min)
			 min = *(I+(i+di)*nc+j+dj);
	     *(O+i*nc+j) = min; 
	 }
     }
}

/*+-------------------------------------------------------------------------+
  | Implementacao da INVERSAO de uma imagem qualquer (binaria ou numerica). |
  | PARAMETROS:                                                             |
  |   I   = ponteiro da imagem (entrada)                                    |
  |   O   = ponteiro da imagem resultado (saida)                            |
  |   nl  = numero de linhas da imagem                                      |
  |   nc  = numero de colunas da imagem                                     |
  |   mn  = maximo nivel de cinza                                           |
  +-------------------------------------------------------------------------+*/
void inverte (int *I, int *O, int nl, int nc, int mn) {
  int i, j;
  for (i = 0; i < nl; i++)
     for (j = 0; j < nc; j++)
	 *(O+i*nc+j) = mn - *(I+i*nc+j);
}

/*+-------------------------------------------------------------------------+
  | Implementacao da transformacao GRADIENTE:                               |
  |      Esta transformacao e' obtida como diferenca entre o resultado da   |
  | DILATACAO e o resultado da EROSAO.                                      |
  |                 GRADIENTE = DILATACAO - EROSAO                          |
  | PARAMETROS:                                                             |
  |   I   = ponteiro da imagem (entrada)                                    |
  |   O   = ponteiro da imagem resultado (saida)                            |
  |   nl  = numero de linhas da imagem                                      |
  |   nc  = numero de colunas da imagem                                     |
  |   mn  = maximo nivel de cinza                                           |
  +-------------------------------------------------------------------------+*/
void gradiente (int *I, int *O, int nl, int nc, int mn) {
  int *D, *E;
  int i, j;
  aloca_memo (&D, nl, nc);
  aloca_memo (&E, nl, nc);
  dilata (I, D, nl, nc);
  erode (I, E, nl, nc, mn);
  for (i = 0; i < nl; i++)
     for (j = 0; j < nc; j++)
          *(O+i*nc+j) = *(D+i*nc+j) - *(E+i*nc+j);
  free (D);
  free (E);
}

/*+-------------------------------------------------------------------------+
  | Implementacao da transformacao DISTANCIA:                               |
  |     Esta transformacao pega uma imagem binaria e transforma numa imagem |
  | em niveis de cinza (numerica), onde cada valor representa a distancia   |
  | dos pixeis caracteristicos (1) do fundo (0).                            |
  | PARAMETROS:                                                             |
  |   I   = ponteiro da imagem (entrada e saida)                            |
  |   nl  = numero de linhas da imagem                                      |
  |   nc  = numero de colunas da imagem                                     |
  |   mn  = maximo nivel de cinza                                           |
  +-------------------------------------------------------------------------+*/
int min (int a, int b, int c) {
  int m;
  if (a < b) m = a; else m = b;
  if (c < m) m = c;
  return m;
}


void distancia (int *I, int nl, int nc, int *mn) {  
  int i, j, maior, I1, I2;
  for (i = 1; i < nl-1; i++)
    for (j = 1; j < nc-1; j++)
       if (*(I+i*nc+j) != 0) {
          I1 = *(I+(i-1)*nc+j) + 1;
          I2 = *(I+i*nc+(j-1)) + 1;
          *(I+i*nc+j) = (I1 < I2) ? I1 : I2; 
       }
  maior = 0;
  for (i = nl-1; i >= 0; i--)
    for (j = nc-1; j >= 0; j--)
       if (*(I+i*nc+j) != 0) {
          I1 = min (*(I+i*nc+j), 
                    *(I+i*nc+(j+1))+1, 
                    *(I+(i+1)*nc+j)+1);
          *(I+i*nc+j) = I1;
          if (I1 > maior) maior = I1;
       }
  *mn = maior;
}
