Home | History | Annotate | Download | only in src
      1 /*M///////////////////////////////////////////////////////////////////////////////////////
      2 //
      3 //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
      4 //
      5 //  By downloading, copying, installing or using the software you agree to this license.
      6 //  If you do not agree to this license, do not download, install,
      7 //  copy or use the software.
      8 //
      9 //
     10 //                        Intel License Agreement
     11 //                For Open Source Computer Vision Library
     12 //
     13 // Copyright (C) 2000, Intel Corporation, all rights reserved.
     14 // Third party copyrights are property of their respective owners.
     15 //
     16 // Redistribution and use in source and binary forms, with or without modification,
     17 // are permitted provided that the following conditions are met:
     18 //
     19 //   * Redistribution's of source code must retain the above copyright notice,
     20 //     this list of conditions and the following disclaimer.
     21 //
     22 //   * Redistribution's in binary form must reproduce the above copyright notice,
     23 //     this list of conditions and the following disclaimer in the documentation
     24 //     and/or other materials provided with the distribution.
     25 //
     26 //   * The name of Intel Corporation may not be used to endorse or promote products
     27 //     derived from this software without specific prior written permission.
     28 //
     29 // This software is provided by the copyright holders and contributors "as is" and
     30 // any express or implied warranties, including, but not limited to, the implied
     31 // warranties of merchantability and fitness for a particular purpose are disclaimed.
     32 // In no event shall the Intel Corporation or contributors be liable for any direct,
     33 // indirect, incidental, special, exemplary, or consequential damages
     34 // (including, but not limited to, procurement of substitute goods or services;
     35 // loss of use, data, or profits; or business interruption) however caused
     36 // and on any theory of liability, whether in contract, strict liability,
     37 // or tort (including negligence or otherwise) arising in any way out of
     38 // the use of this software, even if advised of the possibility of such damage.
     39 //
     40 //M*/
     41 
     42 /****************************************************************************************\
     43 
     44       Calculation of a texture descriptors from GLCM (Grey Level Co-occurrence Matrix'es)
     45       The code was submitted by Daniel Eaton [danieljameseaton (at) yahoo.com]
     46 
     47 \****************************************************************************************/
     48 
     49 #include "_cvaux.h"
     50 
     51 #include <math.h>
     52 #include <assert.h>
     53 
     54 #define CV_MAX_NUM_GREY_LEVELS_8U  256
     55 
     56 struct CvGLCM
     57 {
     58     int matrixSideLength;
     59     int numMatrices;
     60     double*** matrices;
     61 
     62     int  numLookupTableElements;
     63     int  forwardLookupTable[CV_MAX_NUM_GREY_LEVELS_8U];
     64     int  reverseLookupTable[CV_MAX_NUM_GREY_LEVELS_8U];
     65 
     66     double** descriptors;
     67     int numDescriptors;
     68     int descriptorOptimizationType;
     69     int optimizationType;
     70 };
     71 
     72 
     73 static void icvCreateGLCM_LookupTable_8u_C1R( const uchar* srcImageData, int srcImageStep,
     74                                              CvSize srcImageSize, CvGLCM* destGLCM,
     75                                              int* steps, int numSteps, int* memorySteps );
     76 
     77 static void
     78 icvCreateGLCMDescriptors_AllowDoubleNest( CvGLCM* destGLCM, int matrixIndex );
     79 
     80 
     81 CV_IMPL CvGLCM*
     82 cvCreateGLCM( const IplImage* srcImage,
     83               int stepMagnitude,
     84               const int* srcStepDirections,/* should be static array..
     85                                           or if not the user should handle de-allocation */
     86               int numStepDirections,
     87               int optimizationType )
     88 {
     89     static const int defaultStepDirections[] = { 0,1, -1,1, -1,0, -1,-1 };
     90 
     91     int* memorySteps = 0;
     92     CvGLCM* newGLCM = 0;
     93     int* stepDirections = 0;
     94 
     95     CV_FUNCNAME( "cvCreateGLCM" );
     96 
     97     __BEGIN__;
     98 
     99     uchar* srcImageData = 0;
    100     CvSize srcImageSize;
    101     int srcImageStep;
    102     int stepLoop;
    103     const int maxNumGreyLevels8u = CV_MAX_NUM_GREY_LEVELS_8U;
    104 
    105     if( !srcImage )
    106         CV_ERROR( CV_StsNullPtr, "" );
    107 
    108     if( srcImage->nChannels != 1 )
    109         CV_ERROR( CV_BadNumChannels, "Number of channels must be 1");
    110 
    111     if( srcImage->depth != IPL_DEPTH_8U )
    112         CV_ERROR( CV_BadDepth, "Depth must be equal IPL_DEPTH_8U");
    113 
    114     // no Directions provided, use the default ones - 0 deg, 45, 90, 135
    115     if( !srcStepDirections )
    116     {
    117         srcStepDirections = defaultStepDirections;
    118     }
    119 
    120     CV_CALL( stepDirections = (int*)cvAlloc( numStepDirections*2*sizeof(stepDirections[0])));
    121     memcpy( stepDirections, srcStepDirections, numStepDirections*2*sizeof(stepDirections[0]));
    122 
    123     cvGetImageRawData( srcImage, &srcImageData, &srcImageStep, &srcImageSize );
    124 
    125     // roll together Directions and magnitudes together with knowledge of image (step)
    126     CV_CALL( memorySteps = (int*)cvAlloc( numStepDirections*sizeof(memorySteps[0])));
    127 
    128     for( stepLoop = 0; stepLoop < numStepDirections; stepLoop++ )
    129     {
    130         stepDirections[stepLoop*2 + 0] *= stepMagnitude;
    131         stepDirections[stepLoop*2 + 1] *= stepMagnitude;
    132 
    133         memorySteps[stepLoop] = stepDirections[stepLoop*2 + 0]*srcImageStep +
    134                                 stepDirections[stepLoop*2 + 1];
    135     }
    136 
    137     CV_CALL( newGLCM = (CvGLCM*)cvAlloc(sizeof(newGLCM)));
    138     memset( newGLCM, 0, sizeof(newGLCM) );
    139 
    140     newGLCM->matrices = 0;
    141     newGLCM->numMatrices = numStepDirections;
    142     newGLCM->optimizationType = optimizationType;
    143 
    144     if( optimizationType <= CV_GLCM_OPTIMIZATION_LUT )
    145     {
    146         int lookupTableLoop, imageColLoop, imageRowLoop, lineOffset = 0;
    147 
    148         // if optimization type is set to lut, then make one for the image
    149         if( optimizationType == CV_GLCM_OPTIMIZATION_LUT )
    150         {
    151             for( imageRowLoop = 0; imageRowLoop < srcImageSize.height;
    152                                    imageRowLoop++, lineOffset += srcImageStep )
    153             {
    154                 for( imageColLoop = 0; imageColLoop < srcImageSize.width; imageColLoop++ )
    155                 {
    156                     newGLCM->forwardLookupTable[srcImageData[lineOffset+imageColLoop]]=1;
    157                 }
    158             }
    159 
    160             newGLCM->numLookupTableElements = 0;
    161 
    162             for( lookupTableLoop = 0; lookupTableLoop < maxNumGreyLevels8u; lookupTableLoop++ )
    163             {
    164                 if( newGLCM->forwardLookupTable[ lookupTableLoop ] != 0 )
    165                 {
    166                     newGLCM->forwardLookupTable[ lookupTableLoop ] =
    167                         newGLCM->numLookupTableElements;
    168                     newGLCM->reverseLookupTable[ newGLCM->numLookupTableElements ] =
    169                         lookupTableLoop;
    170 
    171                     newGLCM->numLookupTableElements++;
    172                 }
    173             }
    174         }
    175         // otherwise make a "LUT" which contains all the gray-levels (for code-reuse)
    176         else if( optimizationType == CV_GLCM_OPTIMIZATION_NONE )
    177         {
    178             for( lookupTableLoop = 0; lookupTableLoop <maxNumGreyLevels8u; lookupTableLoop++ )
    179             {
    180                 newGLCM->forwardLookupTable[ lookupTableLoop ] = lookupTableLoop;
    181                 newGLCM->reverseLookupTable[ lookupTableLoop ] = lookupTableLoop;
    182             }
    183             newGLCM->numLookupTableElements = maxNumGreyLevels8u;
    184         }
    185 
    186         newGLCM->matrixSideLength = newGLCM->numLookupTableElements;
    187         icvCreateGLCM_LookupTable_8u_C1R( srcImageData, srcImageStep, srcImageSize,
    188                                           newGLCM, stepDirections,
    189                                           numStepDirections, memorySteps );
    190     }
    191     else if( optimizationType == CV_GLCM_OPTIMIZATION_HISTOGRAM )
    192     {
    193         CV_ERROR( CV_StsBadFlag, "Histogram-based method is not implemented" );
    194 
    195     /*  newGLCM->numMatrices *= 2;
    196         newGLCM->matrixSideLength = maxNumGreyLevels8u*2;
    197 
    198         icvCreateGLCM_Histogram_8uC1R( srcImageStep, srcImageSize, srcImageData,
    199                                        newGLCM, numStepDirections,
    200                                        stepDirections, memorySteps );
    201     */
    202     }
    203 
    204     __END__;
    205 
    206     cvFree( &memorySteps );
    207     cvFree( &stepDirections );
    208 
    209     if( cvGetErrStatus() < 0 )
    210     {
    211         cvFree( &newGLCM );
    212     }
    213 
    214     return newGLCM;
    215 }
    216 
    217 
    218 CV_IMPL void
    219 cvReleaseGLCM( CvGLCM** GLCM, int flag )
    220 {
    221     CV_FUNCNAME( "cvReleaseGLCM" );
    222 
    223     __BEGIN__;
    224 
    225     int matrixLoop;
    226 
    227     if( !GLCM )
    228         CV_ERROR( CV_StsNullPtr, "" );
    229 
    230     if( *GLCM )
    231         EXIT; // repeated deallocation: just skip it.
    232 
    233     if( (flag == CV_GLCM_GLCM || flag == CV_GLCM_ALL) && (*GLCM)->matrices )
    234     {
    235         for( matrixLoop = 0; matrixLoop < (*GLCM)->numMatrices; matrixLoop++ )
    236         {
    237             if( (*GLCM)->matrices[ matrixLoop ] )
    238             {
    239                 cvFree( (*GLCM)->matrices[matrixLoop] );
    240                 cvFree( (*GLCM)->matrices + matrixLoop );
    241             }
    242         }
    243 
    244         cvFree( &((*GLCM)->matrices) );
    245     }
    246 
    247     if( (flag == CV_GLCM_DESC || flag == CV_GLCM_ALL) && (*GLCM)->descriptors )
    248     {
    249         for( matrixLoop = 0; matrixLoop < (*GLCM)->numMatrices; matrixLoop++ )
    250         {
    251             cvFree( (*GLCM)->descriptors + matrixLoop );
    252         }
    253         cvFree( &((*GLCM)->descriptors) );
    254     }
    255 
    256     if( flag == CV_GLCM_ALL )
    257     {
    258         cvFree( GLCM );
    259     }
    260 
    261     __END__;
    262 }
    263 
    264 
    265 static void
    266 icvCreateGLCM_LookupTable_8u_C1R( const uchar* srcImageData,
    267                                   int srcImageStep,
    268                                   CvSize srcImageSize,
    269                                   CvGLCM* destGLCM,
    270                                   int* steps,
    271                                   int numSteps,
    272                                   int* memorySteps )
    273 {
    274     int* stepIncrementsCounter = 0;
    275 
    276     CV_FUNCNAME( "icvCreateGLCM_LookupTable_8u_C1R" );
    277 
    278     __BEGIN__;
    279 
    280     int matrixSideLength = destGLCM->matrixSideLength;
    281     int stepLoop, sideLoop1, sideLoop2;
    282     int colLoop, rowLoop, lineOffset = 0;
    283     double*** matrices = 0;
    284 
    285     // allocate memory to the matrices
    286     CV_CALL( destGLCM->matrices = (double***)cvAlloc( sizeof(matrices[0])*numSteps ));
    287     matrices = destGLCM->matrices;
    288 
    289     for( stepLoop=0; stepLoop<numSteps; stepLoop++ )
    290     {
    291         CV_CALL( matrices[stepLoop] = (double**)cvAlloc( sizeof(matrices[0])*matrixSideLength ));
    292         CV_CALL( matrices[stepLoop][0] = (double*)cvAlloc( sizeof(matrices[0][0])*
    293                                                   matrixSideLength*matrixSideLength ));
    294 
    295         memset( matrices[stepLoop][0], 0, matrixSideLength*matrixSideLength*
    296                                           sizeof(matrices[0][0]) );
    297 
    298         for( sideLoop1 = 1; sideLoop1 < matrixSideLength; sideLoop1++ )
    299         {
    300             matrices[stepLoop][sideLoop1] = matrices[stepLoop][sideLoop1-1] + matrixSideLength;
    301         }
    302     }
    303 
    304     CV_CALL( stepIncrementsCounter = (int*)cvAlloc( numSteps*sizeof(stepIncrementsCounter[0])));
    305     memset( stepIncrementsCounter, 0, numSteps*sizeof(stepIncrementsCounter[0]) );
    306 
    307     // generate GLCM for each step
    308     for( rowLoop=0; rowLoop<srcImageSize.height; rowLoop++, lineOffset+=srcImageStep )
    309     {
    310         for( colLoop=0; colLoop<srcImageSize.width; colLoop++ )
    311         {
    312             int pixelValue1 = destGLCM->forwardLookupTable[srcImageData[lineOffset + colLoop]];
    313 
    314             for( stepLoop=0; stepLoop<numSteps; stepLoop++ )
    315             {
    316                 int col2, row2;
    317                 row2 = rowLoop + steps[stepLoop*2 + 0];
    318                 col2 = colLoop + steps[stepLoop*2 + 1];
    319 
    320                 if( col2>=0 && row2>=0 && col2<srcImageSize.width && row2<srcImageSize.height )
    321                 {
    322                     int memoryStep = memorySteps[ stepLoop ];
    323                     int pixelValue2 = destGLCM->forwardLookupTable[ srcImageData[ lineOffset + colLoop + memoryStep ] ];
    324 
    325                     // maintain symmetry
    326                     matrices[stepLoop][pixelValue1][pixelValue2] ++;
    327                     matrices[stepLoop][pixelValue2][pixelValue1] ++;
    328 
    329                     // incremenet counter of total number of increments
    330                     stepIncrementsCounter[stepLoop] += 2;
    331                 }
    332             }
    333         }
    334     }
    335 
    336     // normalize matrices. each element is a probability of gray value i,j adjacency in direction/magnitude k
    337     for( sideLoop1=0; sideLoop1<matrixSideLength; sideLoop1++ )
    338     {
    339         for( sideLoop2=0; sideLoop2<matrixSideLength; sideLoop2++ )
    340         {
    341             for( stepLoop=0; stepLoop<numSteps; stepLoop++ )
    342             {
    343                 matrices[stepLoop][sideLoop1][sideLoop2] /= double(stepIncrementsCounter[stepLoop]);
    344             }
    345         }
    346     }
    347 
    348     destGLCM->matrices = matrices;
    349 
    350     __END__;
    351 
    352     cvFree( &stepIncrementsCounter );
    353 
    354     if( cvGetErrStatus() < 0 )
    355         cvReleaseGLCM( &destGLCM, CV_GLCM_GLCM );
    356 }
    357 
    358 
    359 CV_IMPL void
    360 cvCreateGLCMDescriptors( CvGLCM* destGLCM, int descriptorOptimizationType )
    361 {
    362     CV_FUNCNAME( "cvCreateGLCMDescriptors" );
    363 
    364     __BEGIN__;
    365 
    366     int matrixLoop;
    367 
    368     if( !destGLCM )
    369         CV_ERROR( CV_StsNullPtr, "" );
    370 
    371     if( !(destGLCM->matrices) )
    372         CV_ERROR( CV_StsNullPtr, "Matrices are not allocated" );
    373 
    374     CV_CALL( cvReleaseGLCM( &destGLCM, CV_GLCM_DESC ));
    375 
    376     if( destGLCM->optimizationType != CV_GLCM_OPTIMIZATION_HISTOGRAM )
    377     {
    378         destGLCM->descriptorOptimizationType = destGLCM->numDescriptors = descriptorOptimizationType;
    379     }
    380     else
    381     {
    382         CV_ERROR( CV_StsBadFlag, "Histogram-based method is not implemented" );
    383 //      destGLCM->descriptorOptimizationType = destGLCM->numDescriptors = CV_GLCMDESC_OPTIMIZATION_HISTOGRAM;
    384     }
    385 
    386     CV_CALL( destGLCM->descriptors = (double**)
    387             cvAlloc( destGLCM->numMatrices*sizeof(destGLCM->descriptors[0])));
    388 
    389     for( matrixLoop = 0; matrixLoop < destGLCM->numMatrices; matrixLoop ++ )
    390     {
    391         CV_CALL( destGLCM->descriptors[ matrixLoop ] =
    392                 (double*)cvAlloc( destGLCM->numDescriptors*sizeof(destGLCM->descriptors[0][0])));
    393         memset( destGLCM->descriptors[matrixLoop], 0, destGLCM->numDescriptors*sizeof(double) );
    394 
    395         switch( destGLCM->descriptorOptimizationType )
    396         {
    397             case CV_GLCMDESC_OPTIMIZATION_ALLOWDOUBLENEST:
    398                 icvCreateGLCMDescriptors_AllowDoubleNest( destGLCM, matrixLoop );
    399                 break;
    400             default:
    401                 CV_ERROR( CV_StsBadFlag,
    402                 "descriptorOptimizationType different from CV_GLCMDESC_OPTIMIZATION_ALLOWDOUBLENEST\n"
    403                 "is not supported" );
    404             /*
    405             case CV_GLCMDESC_OPTIMIZATION_ALLOWTRIPLENEST:
    406                 icvCreateGLCMDescriptors_AllowTripleNest( destGLCM, matrixLoop );
    407                 break;
    408             case CV_GLCMDESC_OPTIMIZATION_HISTOGRAM:
    409                 if(matrixLoop < destGLCM->numMatrices>>1)
    410                     icvCreateGLCMDescriptors_Histogram( destGLCM, matrixLoop);
    411                     break;
    412             */
    413         }
    414     }
    415 
    416     __END__;
    417 
    418     if( cvGetErrStatus() < 0 )
    419         cvReleaseGLCM( &destGLCM, CV_GLCM_DESC );
    420 }
    421 
    422 
    423 static void
    424 icvCreateGLCMDescriptors_AllowDoubleNest( CvGLCM* destGLCM, int matrixIndex )
    425 {
    426     int sideLoop1, sideLoop2;
    427     int matrixSideLength = destGLCM->matrixSideLength;
    428 
    429     double** matrix = destGLCM->matrices[ matrixIndex ];
    430     double* descriptors = destGLCM->descriptors[ matrixIndex ];
    431 
    432     double* marginalProbability =
    433         (double*)cvAlloc( matrixSideLength * sizeof(marginalProbability[0]));
    434     memset( marginalProbability, 0, matrixSideLength * sizeof(double) );
    435 
    436     double maximumProbability = 0;
    437     double marginalProbabilityEntropy = 0;
    438     double correlationMean = 0, correlationStdDeviation = 0, correlationProductTerm = 0;
    439 
    440     for( sideLoop1=0; sideLoop1<matrixSideLength; sideLoop1++ )
    441     {
    442         int actualSideLoop1 = destGLCM->reverseLookupTable[ sideLoop1 ];
    443 
    444         for( sideLoop2=0; sideLoop2<matrixSideLength; sideLoop2++ )
    445         {
    446             double entryValue = matrix[ sideLoop1 ][ sideLoop2 ];
    447 
    448             int actualSideLoop2 = destGLCM->reverseLookupTable[ sideLoop2 ];
    449             int sideLoopDifference = actualSideLoop1 - actualSideLoop2;
    450             int sideLoopDifferenceSquared = sideLoopDifference*sideLoopDifference;
    451 
    452             marginalProbability[ sideLoop1 ] += entryValue;
    453             correlationMean += actualSideLoop1*entryValue;
    454 
    455             maximumProbability = MAX( maximumProbability, entryValue );
    456 
    457             if( actualSideLoop2 > actualSideLoop1 )
    458             {
    459                 descriptors[ CV_GLCMDESC_CONTRAST ] += sideLoopDifferenceSquared * entryValue;
    460             }
    461 
    462             descriptors[ CV_GLCMDESC_HOMOGENITY ] += entryValue / ( 1.0 + sideLoopDifferenceSquared );
    463 
    464             if( entryValue > 0 )
    465             {
    466                 descriptors[ CV_GLCMDESC_ENTROPY ] += entryValue * log( entryValue );
    467             }
    468 
    469             descriptors[ CV_GLCMDESC_ENERGY ] += entryValue*entryValue;
    470         }
    471 
    472         if( marginalProbability>0 )
    473             marginalProbabilityEntropy += marginalProbability[ actualSideLoop1 ]*log(marginalProbability[ actualSideLoop1 ]);
    474     }
    475 
    476     marginalProbabilityEntropy = -marginalProbabilityEntropy;
    477 
    478     descriptors[ CV_GLCMDESC_CONTRAST ] += descriptors[ CV_GLCMDESC_CONTRAST ];
    479     descriptors[ CV_GLCMDESC_ENTROPY ] = -descriptors[ CV_GLCMDESC_ENTROPY ];
    480     descriptors[ CV_GLCMDESC_MAXIMUMPROBABILITY ] = maximumProbability;
    481 
    482     double HXY = 0, HXY1 = 0, HXY2 = 0;
    483 
    484     HXY = descriptors[ CV_GLCMDESC_ENTROPY ];
    485 
    486     for( sideLoop1=0; sideLoop1<matrixSideLength; sideLoop1++ )
    487     {
    488         double sideEntryValueSum = 0;
    489         int actualSideLoop1 = destGLCM->reverseLookupTable[ sideLoop1 ];
    490 
    491         for( sideLoop2=0; sideLoop2<matrixSideLength; sideLoop2++ )
    492         {
    493             double entryValue = matrix[ sideLoop1 ][ sideLoop2 ];
    494 
    495             sideEntryValueSum += entryValue;
    496 
    497             int actualSideLoop2 = destGLCM->reverseLookupTable[ sideLoop2 ];
    498 
    499             correlationProductTerm += (actualSideLoop1 - correlationMean) * (actualSideLoop2 - correlationMean) * entryValue;
    500 
    501             double clusterTerm = actualSideLoop1 + actualSideLoop2 - correlationMean - correlationMean;
    502 
    503             descriptors[ CV_GLCMDESC_CLUSTERTENDENCY ] += clusterTerm * clusterTerm * entryValue;
    504             descriptors[ CV_GLCMDESC_CLUSTERSHADE ] += clusterTerm * clusterTerm * clusterTerm * entryValue;
    505 
    506             double HXYValue = marginalProbability[ actualSideLoop1 ] * marginalProbability[ actualSideLoop2 ];
    507             if( HXYValue>0 )
    508             {
    509                 double HXYValueLog = log( HXYValue );
    510                 HXY1 += entryValue * HXYValueLog;
    511                 HXY2 += HXYValue * HXYValueLog;
    512             }
    513         }
    514 
    515         correlationStdDeviation += (actualSideLoop1-correlationMean) * (actualSideLoop1-correlationMean) * sideEntryValueSum;
    516     }
    517 
    518     HXY1 =- HXY1;
    519     HXY2 =- HXY2;
    520 
    521     descriptors[ CV_GLCMDESC_CORRELATIONINFO1 ] = ( HXY - HXY1 ) / ( correlationMean );
    522     descriptors[ CV_GLCMDESC_CORRELATIONINFO2 ] = sqrt( 1.0 - exp( -2.0 * (HXY2 - HXY ) ) );
    523 
    524     correlationStdDeviation = sqrt( correlationStdDeviation );
    525 
    526     descriptors[ CV_GLCMDESC_CORRELATION ] = correlationProductTerm / (correlationStdDeviation*correlationStdDeviation );
    527 
    528     delete [] marginalProbability;
    529 }
    530 
    531 
    532 CV_IMPL double cvGetGLCMDescriptor( CvGLCM* GLCM, int step, int descriptor )
    533 {
    534     double value = DBL_MAX;
    535 
    536     CV_FUNCNAME( "cvGetGLCMDescriptor" );
    537 
    538     __BEGIN__;
    539 
    540     if( !GLCM )
    541         CV_ERROR( CV_StsNullPtr, "" );
    542 
    543     if( !(GLCM->descriptors) )
    544         CV_ERROR( CV_StsNullPtr, "" );
    545 
    546     if( (unsigned)step >= (unsigned)(GLCM->numMatrices))
    547         CV_ERROR( CV_StsOutOfRange, "step is not in 0 .. GLCM->numMatrices - 1" );
    548 
    549     if( (unsigned)descriptor >= (unsigned)(GLCM->numDescriptors))
    550         CV_ERROR( CV_StsOutOfRange, "descriptor is not in 0 .. GLCM->numDescriptors - 1" );
    551 
    552     value = GLCM->descriptors[step][descriptor];
    553 
    554     __END__;
    555 
    556     return value;
    557 }
    558 
    559 
    560 CV_IMPL void
    561 cvGetGLCMDescriptorStatistics( CvGLCM* GLCM, int descriptor,
    562                                double* _average, double* _standardDeviation )
    563 {
    564     CV_FUNCNAME( "cvGetGLCMDescriptorStatistics" );
    565 
    566     if( _average )
    567         *_average = DBL_MAX;
    568 
    569     if( _standardDeviation )
    570         *_standardDeviation = DBL_MAX;
    571 
    572     __BEGIN__;
    573 
    574     int matrixLoop, numMatrices;
    575     double average = 0, squareSum = 0;
    576 
    577     if( !GLCM )
    578         CV_ERROR( CV_StsNullPtr, "" );
    579 
    580     if( !(GLCM->descriptors))
    581         CV_ERROR( CV_StsNullPtr, "Descriptors are not calculated" );
    582 
    583     if( (unsigned)descriptor >= (unsigned)(GLCM->numDescriptors) )
    584         CV_ERROR( CV_StsOutOfRange, "Descriptor index is out of range" );
    585 
    586     numMatrices = GLCM->numMatrices;
    587 
    588     for( matrixLoop = 0; matrixLoop < numMatrices; matrixLoop++ )
    589     {
    590         double temp = GLCM->descriptors[ matrixLoop ][ descriptor ];
    591         average += temp;
    592         squareSum += temp*temp;
    593     }
    594 
    595     average /= numMatrices;
    596 
    597     if( _average )
    598         *_average = average;
    599 
    600     if( _standardDeviation )
    601         *_standardDeviation = sqrt( (squareSum - average*average*numMatrices)/(numMatrices-1));
    602 
    603     __END__;
    604 }
    605 
    606 
    607 CV_IMPL IplImage*
    608 cvCreateGLCMImage( CvGLCM* GLCM, int step )
    609 {
    610     IplImage* dest = 0;
    611 
    612     CV_FUNCNAME( "cvCreateGLCMImage" );
    613 
    614     __BEGIN__;
    615 
    616     float* destData;
    617     int sideLoop1, sideLoop2;
    618 
    619     if( !GLCM )
    620         CV_ERROR( CV_StsNullPtr, "" );
    621 
    622     if( !(GLCM->matrices) )
    623         CV_ERROR( CV_StsNullPtr, "Matrices are not allocated" );
    624 
    625     if( (unsigned)step >= (unsigned)(GLCM->numMatrices) )
    626         CV_ERROR( CV_StsOutOfRange, "The step index is out of range" );
    627 
    628     dest = cvCreateImage( cvSize( GLCM->matrixSideLength, GLCM->matrixSideLength ), IPL_DEPTH_32F, 1 );
    629     destData = (float*)(dest->imageData);
    630 
    631     for( sideLoop1 = 0; sideLoop1 < GLCM->matrixSideLength;
    632                         sideLoop1++, (float*&)destData += dest->widthStep )
    633     {
    634         for( sideLoop2=0; sideLoop2 < GLCM->matrixSideLength; sideLoop2++ )
    635         {
    636             double matrixValue = GLCM->matrices[step][sideLoop1][sideLoop2];
    637             destData[ sideLoop2 ] = (float)matrixValue;
    638         }
    639     }
    640 
    641     __END__;
    642 
    643     if( cvGetErrStatus() < 0 )
    644         cvReleaseImage( &dest );
    645 
    646     return dest;
    647 }
    648 
    649