Skip to content
Snippets Groups Projects
ClassAnalysis.cpp 13.44 KiB
/*
 * Copyright 2011-2012 INSA Rennes
 *
 * This file is part of INSAimage.
 *
 * INSAimage 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.
 *
 * INSAimage 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 INSAimage.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "ClassAnalysis.h"

#include <cstring>
#include <cstdio>
#include <cmath>
#include <cstdlib>

#include "GrayscaleImage.h"

using namespace ClassAnalysis;
using namespace imagein;
using namespace std;

void ClassAnalysis::analyse(int fen, uint8_t *imorig, double *param1, double *param2, int nbl, int nbc ) {

    // Param 1: Will now hold the means
    // Param 2: Will now hold the standard deviations
    if(!( fen < (nbl * 2) && fen < (nbc * 2) )) {
        char buffer[255];
        sprintf( buffer, "Error in ClassAnalysis::analyse:\nfen = %d, nbl = %d, nbc = %d\n", fen, nbl, nbc );
        throw buffer;
    }
//	char nom1[40],nom2[40];
    int fen2,i,j,k,l,nbp;
    long indexy;
    long indexx;
    double moy,sigma;

//	printf("taille de la fenetre locale pour le calcul des parametres :");
//	scanf("%d",&fen);
    if(fen < 3) fen=3;
    if(fen > 15) fen=15;
    fen2 = fen/2;
//	printf("nom de l'image du parametre 1 :");
//	scanf("%s",nom1);
//	printf("nom de l'image du parametre 2 :");
//	scanf("%s",nom2);

    nbp = fen*fen;
    for(i=0 ; i<nbl ; i++)
      for(j=0 ; j<nbc ; j++)
      {
         moy = sigma = 0;

         for(k=-fen2 ; k<fen2+1 ; k++)
            for(l=-fen2 ; l<fen2+1 ; l++)
     {
              indexy = abs((i+k));
                if( indexy >= nbl ) {
                  indexy = 2 * nbl - indexy - 2;
                }
                indexx = abs((j+l));
                if( indexx >= nbc ) {
                  indexx = 2 * nbc - indexx - 2;
                }
                moy = moy + *(imorig+(indexy)*nbc+indexx);
              sigma = sigma+(*(imorig+(indexy)*nbc+indexx)*(*(imorig+(indexy)*nbc+indexx)));
     }
         *(param1+i*nbc+j) = (moy / nbp);
         *(param2+i*nbc+j) = sqrt((double)(sigma/nbp-(moy*moy)/(nbp*nbp)));
      }


    /*
        *learning_result_1 = new ImageFloat;
    (*learning_result_1)->Create( nbc, nbl );
    *learning_result_2 = new ImageFloat;
    (*learning_result_2)->Create( nbc, nbl );
    (*learning_result_1)->setFloatMatrix( param1 );
    (*learning_result_2)->setFloatMatrix( param2 );
        */
    //ecrire_image(p1,nom1,nbc,nbl);
    //ecrire_image(p2,nom2,nbc,nbl);

}

void ClassAnalysis::estimateur(double *param1,double *param2,double moy1[],double var1[],double moy2[],double var2[],int fen,int nbl,int nbc, const vector<Rectangle>& rectangles) {
    long nbp;
    //long fen2;
    double m1,s1,m2,s2;
    int current_rectangle;
    Rectangle rect;


/* estimation des paramtres de chaque classe */
// Each class is a rectangle in the parameter rectangles
    vector<Rectangle>::const_iterator iter;
    current_rectangle = 0;
    for(iter=rectangles.begin();iter!=rectangles.end();++iter) {
        rect = *iter;
        NormalizeRectangle( rect );
        nbp = ((rect.bottom() - rect.top()) + 1) * ((rect.right() - rect.left()) + 1);
        m1 =  m2 = s1 = s2 = 0;
        for(unsigned int i=rect.top() ; i<=rect.bottom() ; i++) {
          for(unsigned int j=rect.left() ; j<=rect.right() ; j++) {
                m1 = m1 + *(param1+i*nbc+j);
                s1 = s1+(*(param1+i*nbc+j)*(*(param1+i*nbc+j)));
                m2 = m2 + *(param2+i*nbc+j);
                s2 = s2+(*(param2+i*nbc+j)*(*(param2+i*nbc+j)));
            }
        }
        moy1[current_rectangle] = (m1 / nbp);
        var1[current_rectangle] = ((double)(s1/nbp-(m1*m1)/(nbp*nbp)));
        if( var1[current_rectangle] > 0 ) {
          var1[current_rectangle] = sqrt( var1[current_rectangle] );
        }
        else {
          var1[current_rectangle] = 0;
        }
        moy2[current_rectangle] = (m2 / nbp);
        var2[current_rectangle] = ((double)(s2/nbp-(m2*m2)/(nbp*nbp)));
        if( var2[current_rectangle] > 0 ) {
          var2[current_rectangle] = sqrt( var2[current_rectangle] );
        }
        else {
          var2[current_rectangle] = 0;
        }
        current_rectangle++;
    }
}
void ClassAnalysis::classif(double *param1,double *param2,double moy1[],double var1[],double moy2[],double var2[],int fen,int nbl,int nbc, Image **classify_result, int num_classes ) {
    //char nom[40];
    int i,j,k,l,numclass;
    double distmin,dist,d1,d2;
    short *resclass;
    double num_class_multiplier = 250.0 / ((double)(num_classes-1));

    //printf("nom de l'image resultat de classification :");
    //scanf("%s",nom);

    resclass = (short *)calloc(nbl*nbc,sizeof(short));

/* classification */
    for(i=0 ; i<nbl ; i++)
    {
      k=i*nbc;
      for(j=0 ; j<nbc ; j++)
      {
         distmin = 10000;
         for(l=0 ; l<num_classes ; l++)
         {
          d1 = (*(param1+k+j) - moy1[l])/var1[l];
            d2 = (*(param2+k+j) - moy2[l])/var2[l];
            dist = sqrt((double)(d1*d1+d2*d2));
            if(dist < distmin)
            {
              distmin = dist;
              numclass = l;
            }
         }
         *(resclass+k+j) = (short)(numclass * num_class_multiplier);
      }
    }

/* sauvegarde image rsultat de classification dans un fichier */
  *classify_result = new GrayscaleImage(nbc, nbl);
//    Pixel pixel;
    int wcounter, hcounter;
    for( hcounter=0; hcounter< nbl; hcounter++ ) {
        for( wcounter=0; wcounter< nbc; wcounter++ ) {
//          pixel.red = resclass[ hcounter * nbc + wcounter  ];
//            pixel.green = pixel.red;
//            pixel.blue = pixel.red;
            (*classify_result)->setPixelAt( wcounter, hcounter, resclass[hcounter * nbc + wcounter] );
        }
    }
//	ecrire_image(resclass,nom,nbc,nbl);

/* libration mmoire alloue */
  free(resclass);
}

void ClassAnalysis::write_to_file( GrayscaleImage *learning, const vector<Rectangle>& rectangles, FILE *f, int learning_fen, Image_t<double> **returnval_mean, Image_t<double> **returnval_stdev ) {
  char buffer[255];
    if(( learning == NULL )) {
        sprintf( buffer, "Error in ClassAnalysis::write_to_file:\nlearning = %p", learning);
        throw buffer;
    }
    if( f == NULL ) {
        throw "Error in ClassAnalysis::write_to_file:\nf = NULL";
    }
    if(!( ( learning_fen & 1 ) == 1 )) {
        sprintf( buffer, "Error in ClassAnalysis::write_to_file:\nlearning_fen = %d", learning_fen );
        throw buffer;
    }
    if( rectangles.empty() ) {
      throw "Error in ClassAnalysis::write_to_file:\nrectangles.empty() = TRUE";
    }

    //Image *learning_result_1;
    //Image *learning_result_2;
    uint8_t *im1;
  double *param1,*param2, *moy1, *var1, *moy2, *var2;
    long nbl,nbc,size,i;

    // entre des paramtres
    nbc = learning->getWidth();
    nbl = learning->getHeight();
    size = nbc * nbl;

    im1 = learning->begin();
    moy1 = new double[ rectangles.size() ];
    var1 = new double[ rectangles.size() ];
    moy2 = new double[ rectangles.size() ];
    var2 = new double[ rectangles.size() ];

    // allocation memoire pour les images des paramtres caractristiques
    param1 = new double[size];
    param2 = new double[size];

// Traitement
    //printf("\n\n- phase d'apprentissage  \n");
    //printf("\n\n- calcul des parametres caracteristiques sur l'image %s\n",nom1);
    analyse(learning_fen, im1,param1,param2,nbl,nbc );

//	printf("\n\n- estimation des parametres caracteristiques  \n");
    estimateur(param1,param2,moy1,var1,moy2,var2,learning_fen,nbl,nbc,rectangles);

    fprintf( f, "MEAN_STDEV\n" );
    fprintf( f, "%d\n", learning_fen );
    fprintf( f, "%lu\n", rectangles.size() );
    vector<Rectangle>::const_iterator iter;
    i = 0;
    for(iter=rectangles.begin();iter!=rectangles.end();++iter) {
      fprintf( f, "%f %f %f %f\n", moy1[i], var1[i], moy2[i], var2[i] );
        i++;
    }

    if( returnval_mean != NULL ) {
        (*returnval_mean) = new Image_t<double>(nbc, nbl, 1, param1);
    }
    if( returnval_stdev != NULL ) {
        (*returnval_stdev) = new Image_t<double>(nbc, nbl, 1, param2);
    }
    /*
    return_string = "valeur des parametres estimes :\n\n";
    for(i=0 ; i<4 ; i++)
    {
      sprintf(buffer, "Classe no %1d \n",i+1);
        return_string = return_string + buffer;
      sprintf(buffer, "parametre 1 ---> moyenne = %5.1f \n",moy1[i]);
      return_string = return_string + buffer;
        sprintf(buffer, "parametre 2 ---> ecart-type = %4.1f\n",var2[i]);
        return_string = return_string + buffer;
    }
*/
    // Erase memory allocated
    delete im1;
    delete moy1;
    delete var1;
    delete moy2;
    delete var2;
    delete param1;
    delete param2;
//	delete learning_result_1;
//	delete learning_result_2;
}

void ClassAnalysis::NormalizeRectangle( Rectangle &rect ) {
  int top, bottom, left, right;
    top = min( rect.top(), rect.bottom() );
    bottom = max( rect.top(), rect.bottom() );
    left = min( rect.left(), rect.right() );
    right = max( rect.left(), rect.right() );
    rect.y = top;
    rect.h = bottom - top;
    rect.x = left;
    rect.w = right - left;
}

Image *ClassAnalysis::classify_from_file( GrayscaleImage *to_classify, FILE *f, int classify_fen, Image_t<double> **returnval_mean, Image_t<double> **returnval_stdev ) {
    if(!( to_classify != NULL )) {
        throw "Error in ClassAnalysis::classify_from_file:\nto_classify = NULL";
    }
    if(!( f != NULL )) {
      throw "Error in ClassAnalysis::classify_from_file:\nf = NULL";
    }
    if(!( ( classify_fen & 1 ) == 1 )) {
        char buffer[255];
        sprintf( buffer, "Error in ClassAnalysis::classify_from_file:\nclassify_fen = %d", classify_fen );
        throw buffer;
    }

    Image *returnval = NULL;
    char buffer[255];
    int num_classes;
    int counter;
    double *param1,*param2, *moy1, *var1, *moy2, *var2;
    long nbl,nbc;
    //long size,i;
    nbl = to_classify->getHeight();
    nbc = to_classify->getWidth();

    fscanf( f, "%s", buffer );
    if( strcmp( buffer, "MEAN_STDEV" ) == 0 ) {
      fscanf( f, "%d", &num_classes ); // Old learning window size
        fscanf( f, "%d", &num_classes );
        if( num_classes <= 0 ) {
          // Invalid number of classes
            return NULL;
        }
        else {
            moy1 = new double[ num_classes ];
            var1 = new double[ num_classes ];
            moy2 = new double[ num_classes ];
            var2 = new double[ num_classes ];
            for( counter=0; counter< num_classes; counter++ ) {
              fscanf( f, "%lf", &moy1[counter] );
                fscanf( f, "%lf", &var1[counter] );
                fscanf( f, "%lf", &moy2[counter] );
                fscanf( f, "%lf", &var2[counter] );
            }
        }
    }
    else {
      // Invalid file type
        return NULL;
    }

    param1 = new double[nbl * nbc ];
    param2 = new double[nbl * nbc ];
    uint8_t *im1 = to_classify->begin();

    analyse(classify_fen, im1,param1,param2,nbl,nbc );
    classif(param1,param2,moy1,var1,moy2,var2,classify_fen,nbl,nbc, &returnval, num_classes );

    if( returnval_mean != NULL ) {
        (*returnval_mean) = new Image_t<double>(nbc, nbl, 1, param1);
    }
    if( returnval_stdev != NULL ) {
        (*returnval_stdev) = new Image_t<double>(nbc, nbl, 1, param2);
    }

    delete im1;
    delete param1;
    delete param2;
    delete moy1;
    delete moy2;
    delete var1;
    delete var2;
    return returnval;
}

string ClassAnalysis::print_file_info( FILE *f ) {
  if(!( f != NULL )) {
        throw "Error in ClassAnalysis::print_file_info:\nf = NULL";
    }
    string returnval;

    int wsize;
    int num_classes;
    char buffer[255];
    double moy1, moy2, var1, var2;
    int counter;
    fscanf( f, "%s", buffer );
    if( strcmp( buffer, "MEAN_STDEV" ) == 0 ) {
      fscanf( f, "%d", &wsize ); // Old learning window size
        sprintf( buffer, "Learning Window Size: %d\n", wsize );
        returnval = returnval + buffer;
        fscanf( f, "%d", &num_classes );
        sprintf( buffer, "Number of Classes: %d\n", num_classes );
        returnval = returnval + buffer;

        if( num_classes <= 0 ) {
          // Invalid number of classes
            returnval = "\n      Invalid number of classes";
        }
        else {
            for( counter=0; counter< num_classes; counter++ ) {
              fscanf( f, "%lf", &moy1 );
                fscanf( f, "%lf", &var1 );
                fscanf( f, "%lf", &moy2 );
                fscanf( f, "%lf", &var2 );
              sprintf( buffer, "---- Class %d:\n", (counter+1) );
                returnval = returnval + buffer;
                sprintf( buffer, "     Mean of means: %f\n", moy1 );
                returnval = returnval + buffer;
                //sprintf( buffer, "     Stdev of means: %f\n", var1 );
                //returnval = returnval + buffer;
                sprintf( buffer, "     Mean of stdevs: %f\n", moy2 );
                returnval = returnval + buffer;
                //sprintf( buffer, "     Stdev of stdevs: %f\n", var2 );
                //returnval = returnval + buffer;
                returnval = returnval + "\n";
            }
        }
    }
    else {
      returnval = "Not a valid classification file\n";
    }

    return returnval;
}