/* KIRSCH filter v1.0.0 Ver.:OK (c) 11/07 - Christos Iosifides */
/*
   Name:   kirsch_8ui
   Version:  1.0.0
   Author:  Christos Iosifidis
   Date:   29/11/07 15:42
   Description: KIRSCH filter on 8bit unsigned int BIL datasets
   Usage: >kirsch_8ui filename_of_the_8bit_unsigned_int_BIL_dataset filename_of_the_16bit_unsigned_int_BIL_kirsched_dataset rows columns bands

   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>

#define kirschconstand 3840
int kirschfilter[8]= {
                         +5, +5, +5, -3, -3, -3, -3, -3
                     }
                     , kirschbuffer[8];

void error(const char *);

int main(int argc, char *argv[]) {
    FILE *fpin, *fpout;
    int rows, cols, bands, win, win_2, rows_1, cols_1, cols2, s, maxs, rows_win_2, cols_win_2, win_1, tmpint;
    unsigned char *in_buffer;
    unsigned short int *out_buffer;
    register int r, c, i, j;

    if (argc!=6)
        error("Usage parameters: Input_image Output_image rows cols bands");

    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");

    cols*=bands;
    rows_1=rows-1;
    cols_1=cols-1;
    cols2=cols<<1;
    win=3;
    win_2=1; /* 3>>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 short int *)malloc(cols*sizeof(unsigned short int)))==NULL)
        error("Not enough memory avaliable for output buffer");

    /* Store 0 in first empty line */
    memset(out_buffer, 0, cols2);
    /* Write first empty line */
    if (fwrite(out_buffer, sizeof(unsigned short), cols, fpout)!=cols)
        error("Bad write to output file 1");
    /* Read first two lines in buffer */
    if (fread(in_buffer, 1, cols2, fpin)!=cols2)
        error("Bad read from input file 1");

    /* For every row in [ 1, rows-1 ] */
    for (r=1;r<rows_1;r++) {
        /* Store first and last pixels */
        out_buffer[0]=out_buffer[cols_1]=0;
        /* Read line in buffer */
        if (fread(in_buffer+cols2, 1, cols, fpin)!=cols)
            error("Bad read from input file 2");
        /* For every column in [ 1, cols-1 ] */
        for (c=1;c<cols_1;c++) {
            /* Store window into kirsch image buffer */
            kirschbuffer[0]=in_buffer[c-1];        //[ 0 *cols+c+ 0 -1];
            kirschbuffer[1]=in_buffer[c];          //[ 0 *cols+c+ 1 -1];
            kirschbuffer[2]=in_buffer[c+1];        //[ 0 *cols+c+ 2 -1];
            kirschbuffer[3]=in_buffer[cols+c+1];   //[ 1 *cols+c+ 2 -1];
            kirschbuffer[4]=in_buffer[cols2+c+1];  //[ 2 *cols+c+ 2 -1];
            kirschbuffer[5]=in_buffer[cols2+c];    //[ 2 *cols+c+ 1 -1];
            kirschbuffer[6]=in_buffer[cols2+c-1];  //[ 2 *cols+c+ 0 -1];
            kirschbuffer[7]=in_buffer[cols+c-1];   //[ 1 *cols+c+ 0 -1];
            /* Compute first kirsch value */
            maxs=0;
            for (i=0;i<8;i++)
                maxs+=kirschbuffer[i]*kirschfilter[i];
            /* Compute rest kirsch values... */
            for (j=1;j<8;j++) {
                /* Scroll kirsch filter */
                tmpint=kirschfilter[0];
                for (i=1;i<8;i++)
                    kirschfilter[i-1]=kirschfilter[i];
                kirschfilter[7]=tmpint;
                /* Compute kirsch value */
                s=0;
                for (i=0;i<8;i++)
                    s+=kirschbuffer[i]*kirschfilter[i];
                if (s>maxs)
                    maxs=s;
            }
            /* Store result */
            out_buffer[c]=(unsigned short int)(maxs+3840); /* = 256 * 5 * 3 */
        }
        /* Scroll win_2 lines up in buffer */
        memcpy(in_buffer, in_buffer+cols, cols2);
        /* Write results */
        if (fwrite(out_buffer, sizeof(unsigned short), cols, fpout)!=cols)
            error("Bad write to output file 2");
    }
    /* Store 0 in last empty line */
    memset(out_buffer, 0, cols2);

    /* Write last empty line */
    if (fwrite(out_buffer, sizeof(unsigned short), cols, fpout)!=cols)
        error("Bad write to output file 3");

    /* Close files and ... */
    fclose(fpin);
    fclose(fpout);
    free(in_buffer);
    free(out_buffer);
    return 0;
}

void error(const char *s) {
    printf("\nKIRSCH_8UI reports: Error: <%s>.\n",s);
    exit(1);
}

