Ask Your Question

Revision history [back]

click to hide/show revision 1
initial version

There is error with cvAlloc in this code. See the following page: http://tech.dir.groups.yahoo.com/group/OpenCV/message/67611?var=1 You should change /opencv/modules/legacy/src/texture.cpp file to the next:

/*******************************************************************************\
*********\

Calculation of a texture descriptors from GLCM (Grey Level Co-occurrence
Matrix'es)
The code was submitted by Daniel Eaton [danieljameseaton@...]

\*******************************************************************************\
*********/

//#include "_cvaux.h"

//#include "legacy.h"
#include "precomp.hpp"

#define CV_MAX_NUM_GREY_LEVELS_8U 256
struct CvGLCM
{
int matrixSideLength;
int numMatrices;
double*** matrices;

int numLookupTableElements;
int forwardLookupTable[CV_MAX_NUM_GREY_LEVELS_8U];
int reverseLookupTable[CV_MAX_NUM_GREY_LEVELS_8U];

double** descriptors;
int numDescriptors;
int descriptorOptimizationType;
int optimizationType;
};

static void icv_CreateGLCM_LookupTable_8u_C1R( const uchar* srcImageData, int
srcImageStep, CvSize srcImageSize,
CvGLCM* destGLCM, int* steps, int numSteps, int* memorySteps );

static void icv_CreateGLCMDescriptors_AllowDoubleNest( CvGLCM* destGLCM, int
matrixIndex );

CvGLCM* cvCreateGLCM( const IplImage* srcImage, int stepMagnitude, const int* srcStepDirections,/* should be static array..or if not the user should handle de-allocation */ int numStepDirections, int optimizationType )
{
static const int defaultStepDirections[] = { 0,1,-1,1,-1,0,-1,-1 };

int* memorySteps = 0;
CvGLCM* newGLCM = 0;
int* stepDirections = 0;

CV_FUNCNAME( "cvCreateGLCM" );

__BEGIN__;

uchar* srcImageData = 0;
CvSize srcImageSize;
int srcImageStep;
int stepLoop;
const int maxNumGreyLevels8u = CV_MAX_NUM_GREY_LEVELS_8U;

if( !srcImage )
CV_ERROR( CV_StsNullPtr, "" );

if( srcImage->nChannels != 1 )
CV_ERROR( CV_BadNumChannels, "Number of channels must be 1");

if( srcImage->depth != IPL_DEPTH_8U )
CV_ERROR( CV_BadDepth, "Depth must be equal IPL_DEPTH_8U");

// no Directions provided, use the default ones - 0 deg, 45, 90, 135
if( !srcStepDirections )
{
srcStepDirections = defaultStepDirections;
}

//CV_CALL( stepDirections = (int*)cvAlloc(numStepDirections*2*sizeof(stepDirections[0])));
CV_CALL( stepDirections = new int
[numStepDirections*2*sizeof(stepDirections[0])]);
memcpy( stepDirections, srcStepDirections,
numStepDirections*2*sizeof(stepDirections[0]));

cvGetImageRawData( srcImage, &srcImageData, &srcImageStep, &srcImageSize );

// roll together Directions and magnitudes together with knowledge of image (step)
// CV_CALL( memorySteps = (int*)cvAlloc(numStepDirections*sizeof(memorySteps[0])));
CV_CALL( memorySteps = new int [ numStepDirections*sizeof(memorySteps[0]) ]);

for( stepLoop = 0; stepLoop < numStepDirections; stepLoop++ )
{
stepDirections[stepLoop*2 + 0] *= stepMagnitude;
stepDirections[stepLoop*2 + 1] *= stepMagnitude;

memorySteps[stepLoop] = stepDirections[stepLoop*2 + 0]*srcImageStep +
stepDirections[stepLoop*2 + 1];
}

//CV_CALL( newGLCM = (CvGLCM*)cvAlloc(sizeof(newGLCM)));
CV_CALL( newGLCM = new CvGLCM [sizeof(newGLCM)] );
memset( newGLCM, 0, sizeof(newGLCM) );

newGLCM->matrices = 0;
newGLCM->numMatrices = numStepDirections;
newGLCM->optimizationType = optimizationType;

if( optimizationType <= CV_GLCM_OPTIMIZATION_LUT )
{
int lookupTableLoop, imageColLoop, imageRowLoop, lineOffset = 0;

// if optimization type is set to lut, then make one for the image
if( optimizationType == CV_GLCM_OPTIMIZATION_LUT )
{
for( imageRowLoop = 0; imageRowLoop < srcImageSize.height;
imageRowLoop++, lineOffset += srcImageStep )
{
for( imageColLoop = 0; imageColLoop < srcImageSize.width;
imageColLoop++ )
{

newGLCM->forwardLookupTable[srcImageData[lineOffset+imageColLoop]]=1;
}
}

newGLCM->numLookupTableElements = 0;

for( lookupTableLoop = 0; lookupTableLoop < maxNumGreyLevels8u;
lookupTableLoop++ )
{
if( newGLCM->forwardLookupTable[ lookupTableLoop ] != 0 )
{
newGLCM->forwardLookupTable[ lookupTableLoop ] =
newGLCM->numLookupTableElements;
newGLCM->reverseLookupTable[ newGLCM->numLookupTableElements
] =
lookupTableLoop;

newGLCM->numLookupTableElements++;
}
}
}
// otherwise make a "LUT" which contains all the gray-levels (forcode-reuse)
else if( optimizationType == CV_GLCM_OPTIMIZATION_NONE )
{
for( lookupTableLoop = 0; lookupTableLoop <maxNumGreyLevels8u;
lookupTableLoop++ )
{
newGLCM->forwardLookupTable[ lookupTableLoop ] =
lookupTableLoop;
newGLCM->reverseLookupTable[ lookupTableLoop ] =
lookupTableLoop;
}
newGLCM->numLookupTableElements = maxNumGreyLevels8u;
}

newGLCM->matrixSideLength = newGLCM->numLookupTableElements;
icv_CreateGLCM_LookupTable_8u_C1R( srcImageData, srcImageStep,srcImageSize,newGLCM, stepDirections,numStepDirections, memorySteps );
}
else if( optimizationType == CV_GLCM_OPTIMIZATION_HISTOGRAM )
{
CV_ERROR( CV_StsBadFlag, "Histogram-based method is not implemented" );

/* newGLCM->numMatrices *= 2;
newGLCM->matrixSideLength = maxNumGreyLevels8u*2;

icv_CreateGLCM_Histogram_8uC1R( srcImageStep, srcImageSize,
srcImageData,
newGLCM, numStepDirections,
stepDirections, memorySteps );
*/
}

__END__;

delete[] memorySteps;
delete[] stepDirections;

if( cvGetErrStatus() < 0 )
{
cvFree( &newGLCM );
}

return newGLCM;
}


void
cv_ReleaseGLCM( CvGLCM** GLCM, int flag )
{
CV_FUNCNAME( "cvReleaseGLCM" );

__BEGIN__;

int matrixLoop;

if( !GLCM )
CV_ERROR( CV_StsNullPtr, "" );

if( *GLCM )
EXIT; // repeated deallocation: just skip it.

if( (flag == CV_GLCM_GLCM || flag == CV_GLCM_ALL) && (*GLCM)->matrices )
{
for( matrixLoop = 0; matrixLoop < (*GLCM)->numMatrices; matrixLoop++ )
{
if( (*GLCM)->matrices[ matrixLoop ] )
{
cvFree( (*GLCM)->matrices[matrixLoop] );
cvFree( (*GLCM)->matrices + matrixLoop );
}
}

cvFree( &((*GLCM)->matrices) );
}

if( (flag == CV_GLCM_DESC || flag == CV_GLCM_ALL) && (*GLCM)->descriptors )
{
for( matrixLoop = 0; matrixLoop < (*GLCM)->numMatrices; matrixLoop++ )
{
cvFree( (*GLCM)->descriptors + matrixLoop );
}
cvFree( &((*GLCM)->descriptors) );
}

if( flag == CV_GLCM_ALL )
{
cvFree( GLCM );
}

__END__;
}


static void
icv_CreateGLCM_LookupTable_8u_C1R( const uchar* srcImageData,
int srcImageStep,
CvSize srcImageSize,
CvGLCM* destGLCM,
int* steps,
int numSteps,
int* memorySteps )
{
int* stepIncrementsCounter = 0;

CV_FUNCNAME( "icvCreateGLCM_LookupTable_8u_C1R" );

__BEGIN__;

int matrixSideLength = destGLCM->matrixSideLength;
int stepLoop, sideLoop1, sideLoop2;
int colLoop, rowLoop, lineOffset = 0;
double*** matrices = 0;

// allocate memory to the matrices
//CV_CALL( destGLCM->matrices = (double***)cvAlloc(sizeof(matrices[0])*numSteps ));
CV_CALL( destGLCM->matrices = new double** [sizeof(matrices[0])*numSteps] );
matrices = destGLCM->matrices;

for( stepLoop=0; stepLoop<numSteps; stepLoop++ )
{
/*CV_CALL( matrices[stepLoop] = (double**)cvAlloc(
sizeof(matrices[0])*matrixSideLength ));
CV_CALL( matrices[stepLoop][0] = (double*)cvAlloc(
sizeof(matrices[0][0])*

matrixSideLength*matrixSideLength ));*/
CV_CALL( matrices[stepLoop] = new double*[sizeof(matrices[0])*matrixSideLength ]);
CV_CALL( matrices[stepLoop][0] = new double[sizeof(matrices[0][0])*matrixSideLength*matrixSideLength ]);

memset( matrices[stepLoop][0], 0, matrixSideLength*matrixSideLength*sizeof(matrices[0][0]) );

for( sideLoop1 = 1; sideLoop1 < matrixSideLength; sideLoop1++ )
{
matrices[stepLoop][sideLoop1] = matrices[stepLoop][sideLoop1-1] +
matrixSideLength;
}
}

//CV_CALL( stepIncrementsCounter = (int*)cvAlloc(numSteps*sizeof(stepIncrementsCounter[0])));
CV_CALL( stepIncrementsCounter = new int [numSteps*sizeof(stepIncrementsCounter[0])]);
memset( stepIncrementsCounter, 0, numSteps*sizeof(stepIncrementsCounter[0])
);

// generate GLCM for each step
for( rowLoop=0; rowLoop<srcImageSize.height; rowLoop++,
lineOffset+=srcImageStep )
{
for( colLoop=0; colLoop<srcImageSize.width; colLoop++ )
{
int pixelValue1 =
destGLCM->forwardLookupTable[srcImageData[lineOffset + colLoop]];

for( stepLoop=0; stepLoop<numSteps; stepLoop++ )
{
int col2, row2;
row2 = rowLoop + steps[stepLoop*2 + 0];
col2 = colLoop + steps[stepLoop*2 + 1];

if( col2>=0 && row2>=0 && col2<srcImageSize.width &&
row2<srcImageSize.height )
{
int memoryStep = memorySteps[ stepLoop ];
int pixelValue2 = destGLCM->forwardLookupTable[
srcImageData[ lineOffset + colLoop + memoryStep ] ];

// maintain symmetry
matrices[stepLoop][pixelValue1][pixelValue2] ++;
matrices[stepLoop][pixelValue2][pixelValue1] ++;

// incremenet counter of total number of increments
stepIncrementsCounter[stepLoop] += 2;
}
}
}
}

// normalize matrices. each element is a probability of gray value i,j adjacency in direction/magnitude k
for( sideLoop1=0; sideLoop1<matrixSideLength; sideLoop1++ )
{
for( sideLoop2=0; sideLoop2<matrixSideLength; sideLoop2++ )
{
for( stepLoop=0; stepLoop<numSteps; stepLoop++ )
{
matrices[stepLoop][sideLoop1][sideLoop2] /=
double(stepIncrementsCounter[stepLoop]);
}
}
}

destGLCM->matrices = matrices;

__END__;

delete[] stepIncrementsCounter;

if( cvGetErrStatus() < 0 )
cv_ReleaseGLCM( &destGLCM, CV_GLCM_GLCM );
}


void
cvCreateGLCMDescriptors( CvGLCM* destGLCM, int descriptorOptimizationType )
{
CV_FUNCNAME( "cvCreateGLCMDescriptors" );

__BEGIN__;

int matrixLoop;

if( !destGLCM )
CV_ERROR( CV_StsNullPtr, "" );

if( !(destGLCM->matrices) )
CV_ERROR( CV_StsNullPtr, "Matrices are not allocated" );

CV_CALL( cv_ReleaseGLCM( &destGLCM, CV_GLCM_DESC ));

if( destGLCM->optimizationType != CV_GLCM_OPTIMIZATION_HISTOGRAM )
{
destGLCM->descriptorOptimizationType = destGLCM->numDescriptors =
descriptorOptimizationType;
}
else
{
CV_ERROR( CV_StsBadFlag, "Histogram-based method is not implemented" );
// destGLCM->descriptorOptimizationType = destGLCM->numDescriptors = CvGLCMDESC_OPTIMIZATION_HISTOGRAM;
}

//CV_CALL( destGLCM->descriptors = (double**)
//cvAlloc( destGLCM->numMatrices*sizeof(destGLCM->descriptors[0])));
CV_CALL( destGLCM->descriptors = new double*
[destGLCM->numMatrices*sizeof(destGLCM->descriptors[0])]);

for( matrixLoop = 0; matrixLoop < destGLCM->numMatrices; matrixLoop ++ )
{
//CV_CALL( destGLCM->descriptors[ matrixLoop ] =
//(double*)cvAlloc(destGLCM->numDescriptors*sizeof(destGLCM->descriptors[0][0])));
CV_CALL( destGLCM->descriptors[ matrixLoop ] = new double
[destGLCM->numDescriptors*sizeof(destGLCM->descriptors[0][0])]);
memset( destGLCM->descriptors[matrixLoop], 0,
destGLCM->numDescriptors*sizeof(double) );

switch( destGLCM->descriptorOptimizationType )
{
case CV_GLCMDESC_OPTIMIZATION_ALLOWDOUBLENEST:
icv_CreateGLCMDescriptors_AllowDoubleNest( destGLCM, matrixLoop);
break;
default:
CV_ERROR( CV_StsBadFlag, "descriptorOptimizationType different from CvGLCMDESC_OPTIMIZATION_ALLOWDOUBLENEST\n is not supported" );
/*
case CvGLCMDESC_OPTIMIZATION_ALLOWTRIPLENEST:
icvCreateGLCMDescriptors_AllowTripleNest( destGLCM, matrixLoop
);
break;
case CvGLCMDESC_OPTIMIZATION_HISTOGRAM:
if(matrixLoop < destGLCM->numMatrices>>1)
icvCreateGLCMDescriptors_Histogram( destGLCM, matrixLoop);
break;
*/
}
}

__END__;

if( cvGetErrStatus() < 0 )
cv_ReleaseGLCM( &destGLCM, CV_GLCM_DESC );
}


static void
icv_CreateGLCMDescriptors_AllowDoubleNest( CvGLCM* destGLCM, int matrixIndex )
{
int sideLoop1, sideLoop2;
int matrixSideLength = destGLCM->matrixSideLength;

double** matrix = destGLCM->matrices[ matrixIndex ];
double* descriptors = destGLCM->descriptors[ matrixIndex ];

//double* marginalProbability =
//(double*)cvAlloc( matrixSideLength * sizeof(marginalProbability[0]));
double* marginalProbability =
new double [matrixSideLength * sizeof(marginalProbability[0])];
memset( marginalProbability, 0, matrixSideLength * sizeof(double) );

double maximumProbability = 0;
double marginalProbabilityEntropy = 0;
double correlationMean = 0, correlationStdDeviation = 0,
correlationProductTerm = 0;

for( sideLoop1=0; sideLoop1<matrixSideLength; sideLoop1++ )
{
int actualSideLoop1 = destGLCM->reverseLookupTable[ sideLoop1 ];

for( sideLoop2=0; sideLoop2<matrixSideLength; sideLoop2++ )
{
double entryValue = matrix[ sideLoop1 ][ sideLoop2 ];

int actualSideLoop2 = destGLCM->reverseLookupTable[ sideLoop2 ];
int sideLoopDifference = actualSideLoop1 - actualSideLoop2;
int sideLoopDifferenceSquared =
sideLoopDifference*sideLoopDifference;

marginalProbability[ sideLoop1 ] += entryValue;
correlationMean += actualSideLoop1*entryValue;

maximumProbability = MAX( maximumProbability, entryValue );

if( actualSideLoop2 > actualSideLoop1 )
{
descriptors[ CV_GLCMDESC_CONTRAST ] += sideLoopDifferenceSquared
* entryValue;
}

descriptors[ CV_GLCMDESC_HOMOGENITY ] += entryValue / ( 1.0 +
sideLoopDifferenceSquared );

if( entryValue > 0 )
{
descriptors[ CV_GLCMDESC_ENTROPY ] += entryValue * log(
entryValue );
}

descriptors[ CV_GLCMDESC_ENERGY ] += entryValue*entryValue;
}

if( marginalProbability>0 )
marginalProbabilityEntropy += marginalProbability[ actualSideLoop1
]*log(marginalProbability[ actualSideLoop1 ]);
}

marginalProbabilityEntropy = -marginalProbabilityEntropy;

descriptors[ CV_GLCMDESC_CONTRAST ] += descriptors[ CV_GLCMDESC_CONTRAST ];
descriptors[ CV_GLCMDESC_ENTROPY ] = -descriptors[ CV_GLCMDESC_ENTROPY ];
descriptors[ CV_GLCMDESC_MAXIMUMPROBABILITY ] = maximumProbability;

double HXY = 0, HXY1 = 0, HXY2 = 0;

HXY = descriptors[ CV_GLCMDESC_ENTROPY ];

for( sideLoop1=0; sideLoop1<matrixSideLength; sideLoop1++ )
{
double sideEntryValueSum = 0;
int actualSideLoop1 = destGLCM->reverseLookupTable[ sideLoop1 ];

for( sideLoop2=0; sideLoop2<matrixSideLength; sideLoop2++ )
{
double entryValue = matrix[ sideLoop1 ][ sideLoop2 ];

sideEntryValueSum += entryValue;

int actualSideLoop2 = destGLCM->reverseLookupTable[ sideLoop2 ];

correlationProductTerm += (actualSideLoop1 - correlationMean) *
(actualSideLoop2 - correlationMean) * entryValue;

double clusterTerm = actualSideLoop1 + actualSideLoop2 -
correlationMean - correlationMean;

descriptors[ CV_GLCMDESC_CLUSTERTENDENCY ] += clusterTerm *
clusterTerm * entryValue;
descriptors[ CV_GLCMDESC_CLUSTERSHADE ] += clusterTerm * clusterTerm
* clusterTerm * entryValue;

double HXYValue = marginalProbability[ actualSideLoop1 ] *
marginalProbability[ actualSideLoop2 ];
if( HXYValue>0 )
{
double HXYValueLog = log( HXYValue );
HXY1 += entryValue * HXYValueLog;
HXY2 += HXYValue * HXYValueLog;
}
}

correlationStdDeviation += (actualSideLoop1-correlationMean) *
(actualSideLoop1-correlationMean) * sideEntryValueSum;
}

HXY1 =- HXY1;
HXY2 =- HXY2;

descriptors[ CV_GLCMDESC_CORRELATIONINFO1 ] = ( HXY - HXY1 ) / (
correlationMean );
descriptors[ CV_GLCMDESC_CORRELATIONINFO2 ] = sqrt( 1.0 - exp( -2.0 * (HXY2
- HXY ) ) );

correlationStdDeviation = sqrt( correlationStdDeviation );

descriptors[ CV_GLCMDESC_CORRELATION ] = correlationProductTerm /
(correlationStdDeviation*correlationStdDeviation );

delete [] marginalProbability;
}


double cvGetGLCMDescriptor( CvGLCM* GLCM, int step, int descriptor )
{
double value = DBL_MAX;

CV_FUNCNAME( "cvGetGLCMDescriptor" );

__BEGIN__;

if( !GLCM )
CV_ERROR( CV_StsNullPtr, "" );

if( !(GLCM->descriptors) )
CV_ERROR( CV_StsNullPtr, "" );

if( (unsigned)step >= (unsigned)(GLCM->numMatrices))
CV_ERROR( CV_StsOutOfRange, "step is not in 0 .. GLCM->numMatrices - 1"
);

if( (unsigned)descriptor >= (unsigned)(GLCM->numDescriptors))
CV_ERROR( CV_StsOutOfRange, "descriptor is not in 0 ..GLCM->numDescriptors - 1" );

value = GLCM->descriptors[step][descriptor];

__END__;

return value;
}


void
cvGetGLCMDescriptorStatistics( CvGLCM* GLCM, int descriptor,
double* _average, double* _standardDeviation )
{
CV_FUNCNAME( "cvGetGLCMDescriptorStatistics" );

if( _average )
*_average = DBL_MAX;

if( _standardDeviation )
*_standardDeviation = DBL_MAX;

__BEGIN__;

int matrixLoop, numMatrices;
double average = 0, squareSum = 0;

if( !GLCM )
CV_ERROR( CV_StsNullPtr, "" );

if( !(GLCM->descriptors))
CV_ERROR( CV_StsNullPtr, "Descriptors are not calculated" );

if( (unsigned)descriptor >= (unsigned)(GLCM->numDescriptors) )
CV_ERROR( CV_StsOutOfRange, "Descriptor index is out of range" );

numMatrices = GLCM->numMatrices;

for( matrixLoop = 0; matrixLoop < numMatrices; matrixLoop++ )
{
double temp = GLCM->descriptors[ matrixLoop ][ descriptor ];
average += temp;
squareSum += temp*temp;
}

average /= numMatrices;

if( _average )
*_average = average;

if( _standardDeviation )
*_standardDeviation = sqrt( (squareSum -
average*average*numMatrices)/(numMatrices-1));

__END__;
}


IplImage*
cvCreateGLCMImage( CvGLCM* GLCM, int step )
{
IplImage* dest = 0;

CV_FUNCNAME( "cvCreateGLCMImage" );

__BEGIN__;

float* destData;
int sideLoop1, sideLoop2;

if( !GLCM )
CV_ERROR( CV_StsNullPtr, "" );

if( !(GLCM->matrices) )
CV_ERROR( CV_StsNullPtr, "Matrices are not allocated" );

if( (unsigned)step >= (unsigned)(GLCM->numMatrices) )
CV_ERROR( CV_StsOutOfRange, "The step index is out of range" );

dest = cvCreateImage( cvSize( GLCM->matrixSideLength, GLCM->matrixSideLength
), IPL_DEPTH_32F, 1 );
destData = (float*)(dest->imageData);

for( sideLoop1 = 0; sideLoop1 < GLCM->matrixSideLength;
sideLoop1++, (float*&)destData += dest->widthStep )
{
for( sideLoop2=0; sideLoop2 < GLCM->matrixSideLength; sideLoop2++ )
{
double matrixValue = GLCM->matrices[step][sideLoop1][sideLoop2];
destData[ sideLoop2 ] = (float)matrixValue;
}
}

__END__;

if( cvGetErrStatus() < 0 )
cvReleaseImage( &dest );

return dest;
}

Main function code:

int main( int argc, char** argv )
{
    char* filename = argc >= 4 ? argv[1] : (char*)"/home/alex/dev/opencv/opencv_extra/testdata/cv/shared/lena.jpg";
    IplImage* inputIm = cvLoadImage(filename);
    IplImage* grayIm = cvCreateImage(cvSize(inputIm->width, inputIm->height), IPL_DEPTH_8U,1);
    cvCvtColor(inputIm, grayIm, CV_RGB2GRAY);
    CvGLCM* glcm = cvCreateGLCM(grayIm,1,NULL,4,CV_GLCM_OPTIMIZATION_LUT);
    cvCreateGLCMDescriptors(glcm, CV_GLCMDESC_OPTIMIZATION_ALLOWDOUBLENEST);
    double d = cvGetGLCMDescriptor(glcm, 0, CV_GLCMDESC_HOMOGENITY );
    double a = 1; double *ave = &a;
    double s = 1; double *sd = &s;
    cvGetGLCMDescriptorStatistics(glcm, CV_GLCMDESC_ENERGY, ave, sd);
    cout << *ave << " " << *sd;
    return 0;
}