/* Morphology Dilation v1.0.0 Ver.:OK (c) 12/07 - Christos Iosifides */
/*
   Name:   Morphology Dilation_8UI
   Version:  1.0.0
   Author:  Christos Iosifidis
   Date:   04/12/07 11:43
   Description: Mathematical morphology operation Dilation on 8bit unsigned int BIL datasets
   Usage: >M_Dilation_8ui filename_of_the_8bit_unsigned_int_BIL_dataset filename_of_the_8bit_BIL_Dilated_dataset rows columns bands structured_element

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void error(const char *);

int main(int argc, char *argv[]) {
    FILE *fpin, *fpout;
    int rows, cols, bands, win, win_1, win_2, rows_1, cols_1, cols2, rows_win_2, cols_win_2;
    int X, XX, cols__win_1;
    unsigned char *in_buffer, *out_buffer, *s_element;
    register int r, c, i, j;

    /* Check and read argument list items */
    if (argc!=7)
        error("Usage parameters: Input_image Output_image rows cols bands structure_element");

    rows=atoi(argv[3]);
    cols=atoi(argv[4]);
    bands=atoi(argv[5]);
    if (rows<3)
        error("rows must be larger than 3");
    if (cols<3)
        error("columns must be larger than 3");
    if (bands<1)
        error("bands must be more than 1");

    /* Compute helpfull variables */
    cols*=bands;
    rows_1=rows-1;
    cols_1=cols-1;
    cols2=cols<<1;

    /* Open input element file */
    if ((fpin=fopen(argv[6],"r"))==NULL)
        error("Bad input element file name");
    /* Read structuring element size */
    if (fscanf(fpin,"%d",&win)!=1)
        error("Bad element file read 1");
    /* Check structuring element size */
    if (win<3 && win%2==0)
        error("Element size must be odd and greater or equal to 3");
    /* Allocate structuring element memory */
    if ((s_element=(unsigned char *)malloc(win*win))==NULL)
        error("Not enough memory avaliable for structuring element");
    /* Read structuring element */
    for (i=0;i<win;i++)
        for (j=0;j<win;j++) {
            if (fscanf(fpin,"%d",&X)!=1)
                error("Bad element file read 2");
            s_element[i*win+j]=X?1:0;
        }
    /* Close input element file */
    fclose(fpin);

    win_2=win>>1;
    win_1=win-1;
    rows_win_2=rows-win_2;
    cols_win_2=cols-win_2;
    cols__win_1=cols*win_1;

    /* Allocate input buffer */
    if ((in_buffer=(unsigned char *)malloc(win*cols))==NULL)
        error("Not enough memory avaliable for input buffer");
    /* Open input image */
    if ((fpin=fopen(argv[1],"rb"))==NULL)
        error("Bad input file name");
    /* Open output image */
    if ((fpout=fopen(argv[2],"wb"))==NULL)
        error("Bad output file open");
    /* Allocate output file */
    if ((out_buffer=(unsigned char *)malloc(cols))==NULL)
        error("Not enough memory avaliable for output buffer");

    /* Store 0 in first empty line */
    memset(out_buffer, 0, cols);
    /* Write first win/2 empty lines */
    for (i=0;i<win_2;i++)
        if (fwrite(out_buffer, sizeof(unsigned char), cols, fpout)!=cols)
            error("Bad write to output file 1");
    /* Read first win-1 lines in buffer */
    if (fread(in_buffer, 1, cols__win_1, fpin)!=cols__win_1)
        error("Bad read from input file 1");

    /* For every row in [ win_2, rows-win_2 ] */
    for (r=win_2;r<rows_win_2;r++) {
        /* Store first and last pixels */
        for (i=0;i<win_2;i++)
            out_buffer[i]=out_buffer[cols-i-1]=0;
        /* Read line in buffer */
        if (fread(in_buffer+cols__win_1, 1, cols, fpin)!=cols)
            error("Bad read from input file 2");
        /* For every column in [ win_2, cols-win_2 ] */
        for (c=win_2;c<cols_win_2;c++) {

            /* For every surrounding pixel in structure element */
            X=in_buffer[cols_win_2+c];
            for (i=0;i<win;i++)
                for (j=0;j<win;j++)
                    if (s_element[i*win+j]) {
                        XX=in_buffer[c-win_2+i*cols+j];
                        if (X>XX)
                            X=XX;
                    }
            /* Store result */
            out_buffer[c]=(unsigned char)( X );
        }
        /* Scroll cols__win_1 lines up in buffer */
        memcpy(in_buffer, in_buffer+cols, cols__win_1 );
        /* Write results */
        if (fwrite(out_buffer, sizeof(unsigned char), cols, fpout)!=cols)
            error("Bad write to output file 2");
    }
    /* Store 0 in last empty line */
    memset(out_buffer, 0, cols);
    /* Write last win/2 empty lines */
    for (i=0;i<win_2;i++)
        if (fwrite(out_buffer, sizeof(unsigned char), cols, fpout)!=cols)
            error("Bad write to output file 3");

    /* Close files and ... */
    fclose(fpin);
    fclose(fpout);
    free(in_buffer);
    free(out_buffer);
    free(s_element);
    return 0;
}

void error(const char *s) {
    printf("\nM_Dilation_8UI reports: Error: <%s>.\n",s);
    exit(1);
}

