
/* =========================================================================== *
|                                                                              |
|  Copyright (c) 2003, by members of University of Arizona Computer Vision     |
|  group (the authors) including                                               ||
|        Kobus Barnard.                                                        |
|                                                                              |
|  For use outside the University of Arizona Computer Vision group please      |
|  contact Kobus Barnard.                                                      |
|                                                                              |
* =========================================================================== */

/*
 * This is an example program to get help those wanting to try using the vision
 * group's software library. This library is currently undergoing adaptation
 * from a bunch of research code written by Kobus and others to a comprehensive
 * library to support the acitivities of the vision group. Thus there will be
 * problems--please report them--and have some patience. Thanks! 
 *
 *                                    Resources
 * 
 * Manpages (MANPATH ~kobus/doc/man)
 *    Start with a "man kjb". Note that the first part of the document is a bit
 *    overwhelming, as it is geared towards writing substantive vision
 *    copmponents shared with the group and/or, writing code for the library
 *    itself (hence this example!!!). This document essentially gives you a
 *    template for the "INCLUDE AND LOAD" strategy described by "man kjb". 
 *
 *    A key point is that "man kjb" gives a machine generated list of all
 *    routines which have at least minimal documentation. (Perhaps 1/2 of the
 *    routines of interest are documented.) 
 *
 *    Note that there are man pages for the main data types. In particular, you
 *    can do:
 *        man Vector
 *        man Matrix
 *        man KJB_image
 *        man Pixel
 *
 * Other documenation
 *    There are some documentation files which attempt to explain some of the
 *    less conventional things about the library in the following directory:
 *        ~kobus/doc/programming
 *    I wrote it a few years back--hopefully it is not too out of date. 
 *
 * The accomponying file "compile_line" gives the incantation to compile this
 * program. It is:
 *

    gcc -W -Wall -ansi -DLINUX_X86_64 -DLINUX_X86_64_C2 \
        -DHAVE_TIFF -DHAVE_JPEG -DHAVE_SLATEC -DHAVE_LAPACK \
        -I ~kobus/include/kjb \
        example.c \
        -L ~kobus/load/linux_x86_64_c2 \
        -L/usr/X11R6/lib/ \
        -lKJB -lXext -lX11 -lcurses  -llapack -lblas -ltiff -ljpeg  -lg2c -lm \
        -o example 

 *    
 *                         What the program does
 *
 *  The program reads a matrix from the file "matrix.txt", insisting that the
 *  matrix has at least 2 columns, and at least as many rows as columns. (An
 *  example can be found in "matrix.txt"). Having read the matrix, it sets the
 *  upper left corner element to 10, and switches columns one and two. Having
 *  done that, it computes the transpose multiplied by the matrix, and finds the
 *  eigenvectors and eigenvalues of the result. 
 *
 *  The program then checks for a file "image.tiff" in the current directory. If
 *  it exists, then it read it, averages 2 by 2 pixels blocks to reduce the
 *  size, and convolves it with a Gaussian filter which blurs it, displays the
 *  result, and also writes it to "result.tiff". 
 *
 *                         ONE SLIGHTLY TRICKY BIT
 *
 *  I like to check the return values of functions. To keep the example short, I
 *  have employed an ugly looking macro EPETE, which checks for error return,
 *  and if there is one, prints a message and forces a program exit. To
 *  understand what the code does when there are no error conditions, you can
 *  ignore the wrapper. (A C++ programmer would likely handle this with
 *  exceptions which has advantages and disadvantages). 
*/

/* Either include specific .h files, or the whole lot with kjb.h */

#include "i/i_incl.h"
#include "m/m_incl.h"
#include "n/n_incl.h"
/*
#include "kjb.h"
*/

int main(int argc, char** argv)
{
    /* Important note: These things need to be initialzed to NULL !!! */
    Matrix* mp = NULL;
    Matrix* square_mp = NULL;
    Vector* col1_vp = NULL;
    Vector* col2_vp = NULL;
    Matrix* eigen_vectors_mp = NULL;
    Vector* eigen_values_vp = NULL;
    KJB_image* ip = NULL;
    KJB_image* result_ip = NULL;

    
    /* Not absolutely necessary, but recommended. */
    kjb_init();  

    /* * EPETE just wraps the function in case of error. (See comment above). */
    EPETE(read_matrix(&mp, "matrix.txt"));

    if ((mp->num_rows < mp->num_cols) || (mp->num_cols < 2))
    {
        p_stderr("This program needs a matrix with at least two columns\n");
        p_stderr("and at least as many rows as columns.\n");
        kjb_exit(EXIT_FAILURE);
    }

    /* Set first element to 10 */

    mp->elements[ 0 ][ 0 ] = 10;

    /* Swap the columns one and two. */
    EPETE(get_matrix_col(&col1_vp, mp, 0));
    EPETE(get_matrix_col(&col2_vp, mp, 1));
    EPETE(put_matrix_col(mp, col1_vp, 1));
    EPETE(put_matrix_col(mp, col2_vp, 0));

    /* * Write the result to stdout to check it.  */
    pso("The mucked matrix:\n");     /* This is an extended printf */
    EPETE(write_matrix(mp, NULL)); 

    /* * Put (transpose(mp))*mp into square_mp.  */
    EPETE(multiply_with_transpose(&square_mp, mp, mp)); 

    /* * Find the eigen-values and eigen-vectors.  */
    EPETE(diagonalize(square_mp, &eigen_vectors_mp, &eigen_values_vp));

    /* * Lets have a look.  */
    pso("\nThe eigenvalues (note that we do biggest first--opposite of Matlab:\n");   
    EPETE(write_col_vector(eigen_values_vp, NULL));
    pso("\nThe eigenvectors:\n");   
    EPETE(write_matrix(eigen_vectors_mp, NULL));
    pso("\n");   
    
    if (kjb_read_image_2(&ip, "image.tiff") == ERROR)
    {
        kjb_print_error();
    }
    else
    {
        EPETE(ave_image(&result_ip, ip, 2 , 2));
        EPETE(ow_gauss_convolve_image(result_ip, 4.0));

        /* This uses a pipe to an appropriate display program which has to be in
         * your path. */
        EPETE(kjb_display_image(result_ip, (char*)NULL));

        /* The display of the image will die with the program. If you want to
         * have the display of the image survie, you would use
         
        EPETE(fork_display_image(result_ip, (char*)NULL));

        *  However, here we will ask the user to tell use that they are done
        *  looking at it:
        */
        prompt_to_continue();

        /* Note that the image format is specifed by the suffix, so we get a
         * tiff image (ImageMagick convention).  */
        EPETE(kjb_write_image(result_ip, "result.tiff"));
    }
    
    /*
     * Don't forget to clean up (OK, not absolutely necessary, as the program is
     * about to end, but a good habbit). 
    */

    free_matrix(mp);
    free_matrix(square_mp);
    free_matrix(eigen_vectors_mp);

    free_vector(eigen_values_vp);
    free_vector(col1_vp);
    free_vector(col2_vp);

    kjb_free_image(result_ip);
    kjb_free_image(ip);

    /* Normally not needed but recommended just in case--doing it twice is OK.*/
    kjb_cleanup();

    return EXIT_SUCCESS;
}
















