| /*M/////////////////////////////////////////////////////////////////////////////////////// |
| // |
| // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. |
| // |
| // By downloading, copying, installing or using the software you agree to this license. |
| // If you do not agree to this license, do not download, install, |
| // copy or use the software. |
| // |
| // |
| // Intel License Agreement |
| // For Open Source Computer Vision Library |
| // |
| // Copyright (C) 2000, Intel Corporation, all rights reserved. |
| // Third party copyrights are property of their respective owners. |
| // |
| // Redistribution and use in source and binary forms, with or without modification, |
| // are permitted provided that the following conditions are met: |
| // |
| // * Redistribution's of source code must retain the above copyright notice, |
| // this list of conditions and the following disclaimer. |
| // |
| // * Redistribution's in binary form must reproduce the above copyright notice, |
| // this list of conditions and the following disclaimer in the documentation |
| // and/or other materials provided with the distribution. |
| // |
| // * The name of Intel Corporation may not be used to endorse or promote products |
| // derived from this software without specific prior written permission. |
| // |
| // This software is provided by the copyright holders and contributors "as is" and |
| // any express or implied warranties, including, but not limited to, the implied |
| // warranties of merchantability and fitness for a particular purpose are disclaimed. |
| // In no event shall the Intel Corporation or contributors be liable for any direct, |
| // indirect, incidental, special, exemplary, or consequential damages |
| // (including, but not limited to, procurement of substitute goods or services; |
| // loss of use, data, or profits; or business interruption) however caused |
| // and on any theory of liability, whether in contract, strict liability, |
| // or tort (including negligence or otherwise) arising in any way out of |
| // the use of this software, even if advised of the possibility of such damage. |
| // |
| //M*/ |
| #include "_cv.h" |
| |
| /* Creates new histogram */ |
| CvHistogram * |
| cvCreateHist( int dims, int *sizes, CvHistType type, float** ranges, int uniform ) |
| { |
| CvHistogram *hist = 0; |
| |
| CV_FUNCNAME( "cvCreateHist" ); |
| __BEGIN__; |
| |
| if( (unsigned)dims > CV_MAX_DIM ) |
| CV_ERROR( CV_BadOrder, "Number of dimensions is out of range" ); |
| |
| if( !sizes ) |
| CV_ERROR( CV_HeaderIsNull, "Null <sizes> pointer" ); |
| |
| CV_CALL( hist = (CvHistogram *)cvAlloc( sizeof( CvHistogram ))); |
| |
| hist->type = CV_HIST_MAGIC_VAL; |
| hist->thresh2 = 0; |
| hist->bins = 0; |
| if( type == CV_HIST_ARRAY ) |
| { |
| CV_CALL( hist->bins = cvInitMatNDHeader( &hist->mat, dims, sizes, |
| CV_HIST_DEFAULT_TYPE )); |
| CV_CALL( cvCreateData( hist->bins )); |
| } |
| else if( type == CV_HIST_SPARSE ) |
| { |
| CV_CALL( hist->bins = cvCreateSparseMat( dims, sizes, CV_HIST_DEFAULT_TYPE )); |
| } |
| else |
| { |
| CV_ERROR( CV_StsBadArg, "Invalid histogram type" ); |
| } |
| |
| if( ranges ) |
| CV_CALL( cvSetHistBinRanges( hist, ranges, uniform )); |
| |
| __END__; |
| |
| if( cvGetErrStatus() < 0 ) |
| cvReleaseHist( &hist ); |
| |
| return hist; |
| } |
| |
| |
| /* Creates histogram wrapping header for given array */ |
| CV_IMPL CvHistogram* |
| cvMakeHistHeaderForArray( int dims, int *sizes, CvHistogram *hist, |
| float *data, float **ranges, int uniform ) |
| { |
| CvHistogram* result = 0; |
| |
| CV_FUNCNAME( "cvMakeHistHeaderForArray" ); |
| |
| __BEGIN__; |
| |
| if( !hist ) |
| CV_ERROR( CV_StsNullPtr, "Null histogram header pointer" ); |
| |
| if( !data ) |
| CV_ERROR( CV_StsNullPtr, "Null data pointer" ); |
| |
| hist->thresh2 = 0; |
| hist->type = CV_HIST_MAGIC_VAL; |
| CV_CALL( hist->bins = cvInitMatNDHeader( &hist->mat, dims, sizes, |
| CV_HIST_DEFAULT_TYPE, data )); |
| |
| if( ranges ) |
| { |
| if( !uniform ) |
| CV_ERROR( CV_StsBadArg, "Only uniform bin ranges can be used here " |
| "(to avoid memory allocation)" ); |
| CV_CALL( cvSetHistBinRanges( hist, ranges, uniform )); |
| } |
| |
| result = hist; |
| |
| __END__; |
| |
| if( cvGetErrStatus() < 0 && hist ) |
| { |
| hist->type = 0; |
| hist->bins = 0; |
| } |
| |
| return result; |
| } |
| |
| |
| CV_IMPL void |
| cvReleaseHist( CvHistogram **hist ) |
| { |
| CV_FUNCNAME( "cvReleaseHist" ); |
| |
| __BEGIN__; |
| |
| if( !hist ) |
| CV_ERROR( CV_StsNullPtr, "" ); |
| |
| if( *hist ) |
| { |
| CvHistogram* temp = *hist; |
| |
| if( !CV_IS_HIST(temp)) |
| CV_ERROR( CV_StsBadArg, "Invalid histogram header" ); |
| |
| *hist = 0; |
| |
| if( CV_IS_SPARSE_HIST( temp )) |
| cvRelease( &temp->bins ); |
| else |
| { |
| cvReleaseData( temp->bins ); |
| temp->bins = 0; |
| } |
| |
| if( temp->thresh2 ) |
| cvFree( &temp->thresh2 ); |
| |
| cvFree( &temp ); |
| } |
| |
| __END__; |
| } |
| |
| CV_IMPL void |
| cvClearHist( CvHistogram *hist ) |
| { |
| CV_FUNCNAME( "cvClearHist" ); |
| |
| __BEGIN__; |
| |
| if( !CV_IS_HIST(hist) ) |
| CV_ERROR( CV_StsBadArg, "Invalid histogram header" ); |
| |
| cvZero( hist->bins ); |
| |
| __END__; |
| } |
| |
| |
| // Clears histogram bins that are below than threshold |
| CV_IMPL void |
| cvThreshHist( CvHistogram* hist, double thresh ) |
| { |
| CV_FUNCNAME( "cvThreshHist" ); |
| |
| __BEGIN__; |
| |
| if( !CV_IS_HIST(hist) ) |
| CV_ERROR( CV_StsBadArg, "Invalid histogram header" ); |
| |
| if( !CV_IS_SPARSE_MAT(hist->bins) ) |
| { |
| CvMat mat; |
| CV_CALL( cvGetMat( hist->bins, &mat, 0, 1 )); |
| CV_CALL( cvThreshold( &mat, &mat, thresh, 0, CV_THRESH_TOZERO )); |
| } |
| else |
| { |
| CvSparseMat* mat = (CvSparseMat*)hist->bins; |
| CvSparseMatIterator iterator; |
| CvSparseNode *node; |
| |
| for( node = cvInitSparseMatIterator( mat, &iterator ); |
| node != 0; node = cvGetNextSparseNode( &iterator )) |
| { |
| float* val = (float*)CV_NODE_VAL( mat, node ); |
| if( *val <= thresh ) |
| *val = 0; |
| } |
| } |
| |
| __END__; |
| } |
| |
| |
| // Normalizes histogram (make sum of the histogram bins == factor) |
| CV_IMPL void |
| cvNormalizeHist( CvHistogram* hist, double factor ) |
| { |
| double sum = 0; |
| |
| CV_FUNCNAME( "cvNormalizeHist" ); |
| __BEGIN__; |
| |
| if( !CV_IS_HIST(hist) ) |
| CV_ERROR( CV_StsBadArg, "Invalid histogram header" ); |
| |
| if( !CV_IS_SPARSE_HIST(hist) ) |
| { |
| CvMat mat; |
| CV_CALL( cvGetMat( hist->bins, &mat, 0, 1 )); |
| CV_CALL( sum = cvSum( &mat ).val[0] ); |
| if( fabs(sum) < DBL_EPSILON ) |
| sum = 1; |
| CV_CALL( cvScale( &mat, &mat, factor/sum, 0 )); |
| } |
| else |
| { |
| CvSparseMat* mat = (CvSparseMat*)hist->bins; |
| CvSparseMatIterator iterator; |
| CvSparseNode *node; |
| float scale; |
| |
| for( node = cvInitSparseMatIterator( mat, &iterator ); |
| node != 0; node = cvGetNextSparseNode( &iterator )) |
| { |
| sum += *(float*)CV_NODE_VAL(mat,node); |
| } |
| |
| if( fabs(sum) < DBL_EPSILON ) |
| sum = 1; |
| scale = (float)(factor/sum); |
| |
| for( node = cvInitSparseMatIterator( mat, &iterator ); |
| node != 0; node = cvGetNextSparseNode( &iterator )) |
| { |
| *(float*)CV_NODE_VAL(mat,node) *= scale; |
| } |
| } |
| |
| __END__; |
| } |
| |
| |
| // Retrieves histogram global min, max and their positions |
| CV_IMPL void |
| cvGetMinMaxHistValue( const CvHistogram* hist, |
| float *value_min, float* value_max, |
| int* idx_min, int* idx_max ) |
| { |
| double minVal, maxVal; |
| |
| CV_FUNCNAME( "cvGetMinMaxHistValue" ); |
| |
| __BEGIN__; |
| |
| int i, dims, size[CV_MAX_DIM]; |
| |
| if( !CV_IS_HIST(hist) ) |
| CV_ERROR( CV_StsBadArg, "Invalid histogram header" ); |
| |
| dims = cvGetDims( hist->bins, size ); |
| |
| if( !CV_IS_SPARSE_HIST(hist) ) |
| { |
| CvMat mat; |
| CvPoint minPt, maxPt; |
| |
| CV_CALL( cvGetMat( hist->bins, &mat, 0, 1 )); |
| CV_CALL( cvMinMaxLoc( &mat, &minVal, &maxVal, &minPt, &maxPt )); |
| |
| if( dims == 1 ) |
| { |
| if( idx_min ) |
| *idx_min = minPt.y + minPt.x; |
| if( idx_max ) |
| *idx_max = maxPt.y + maxPt.x; |
| } |
| else if( dims == 2 ) |
| { |
| if( idx_min ) |
| idx_min[0] = minPt.y, idx_min[1] = minPt.x; |
| if( idx_max ) |
| idx_max[0] = maxPt.y, idx_max[1] = maxPt.x; |
| } |
| else if( idx_min || idx_max ) |
| { |
| int imin = minPt.y*mat.cols + minPt.x; |
| int imax = maxPt.y*mat.cols + maxPt.x; |
| int i; |
| |
| for( i = dims - 1; i >= 0; i-- ) |
| { |
| if( idx_min ) |
| { |
| int t = imin / size[i]; |
| idx_min[i] = imin - t*size[i]; |
| imin = t; |
| } |
| |
| if( idx_max ) |
| { |
| int t = imax / size[i]; |
| idx_max[i] = imax - t*size[i]; |
| imax = t; |
| } |
| } |
| } |
| } |
| else |
| { |
| CvSparseMat* mat = (CvSparseMat*)hist->bins; |
| CvSparseMatIterator iterator; |
| CvSparseNode *node; |
| int minv = INT_MAX; |
| int maxv = INT_MIN; |
| CvSparseNode* minNode = 0; |
| CvSparseNode* maxNode = 0; |
| const int *_idx_min = 0, *_idx_max = 0; |
| Cv32suf m; |
| |
| for( node = cvInitSparseMatIterator( mat, &iterator ); |
| node != 0; node = cvGetNextSparseNode( &iterator )) |
| { |
| int value = *(int*)CV_NODE_VAL(mat,node); |
| value = CV_TOGGLE_FLT(value); |
| if( value < minv ) |
| { |
| minv = value; |
| minNode = node; |
| } |
| |
| if( value > maxv ) |
| { |
| maxv = value; |
| maxNode = node; |
| } |
| } |
| |
| if( minNode ) |
| { |
| _idx_min = CV_NODE_IDX(mat,minNode); |
| _idx_max = CV_NODE_IDX(mat,maxNode); |
| m.i = CV_TOGGLE_FLT(minv); minVal = m.f; |
| m.i = CV_TOGGLE_FLT(maxv); maxVal = m.f; |
| } |
| else |
| { |
| minVal = maxVal = 0; |
| } |
| |
| for( i = 0; i < dims; i++ ) |
| { |
| if( idx_min ) |
| idx_min[i] = _idx_min ? _idx_min[i] : -1; |
| if( idx_max ) |
| idx_max[i] = _idx_max ? _idx_max[i] : -1; |
| } |
| } |
| |
| if( value_min ) |
| *value_min = (float)minVal; |
| |
| if( value_max ) |
| *value_max = (float)maxVal; |
| |
| __END__; |
| } |
| |
| |
| // Compares two histograms using one of a few methods |
| CV_IMPL double |
| cvCompareHist( const CvHistogram* hist1, |
| const CvHistogram* hist2, |
| int method ) |
| { |
| double _result = -1; |
| |
| CV_FUNCNAME( "cvCompareHist" ); |
| |
| __BEGIN__; |
| |
| int i, dims1, dims2; |
| int size1[CV_MAX_DIM], size2[CV_MAX_DIM], total = 1; |
| double result = 0; |
| |
| if( !CV_IS_HIST(hist1) || !CV_IS_HIST(hist2) ) |
| CV_ERROR( CV_StsBadArg, "Invalid histogram header[s]" ); |
| |
| if( CV_IS_SPARSE_MAT(hist1->bins) != CV_IS_SPARSE_MAT(hist2->bins)) |
| CV_ERROR(CV_StsUnmatchedFormats, "One of histograms is sparse and other is not"); |
| |
| CV_CALL( dims1 = cvGetDims( hist1->bins, size1 )); |
| CV_CALL( dims2 = cvGetDims( hist2->bins, size2 )); |
| |
| if( dims1 != dims2 ) |
| CV_ERROR( CV_StsUnmatchedSizes, |
| "The histograms have different numbers of dimensions" ); |
| |
| for( i = 0; i < dims1; i++ ) |
| { |
| if( size1[i] != size2[i] ) |
| CV_ERROR( CV_StsUnmatchedSizes, "The histograms have different sizes" ); |
| total *= size1[i]; |
| } |
| |
| |
| if( !CV_IS_SPARSE_MAT(hist1->bins)) |
| { |
| union { float* fl; uchar* ptr; } v; |
| float *ptr1, *ptr2; |
| v.fl = 0; |
| CV_CALL( cvGetRawData( hist1->bins, &v.ptr )); |
| ptr1 = v.fl; |
| CV_CALL( cvGetRawData( hist2->bins, &v.ptr )); |
| ptr2 = v.fl; |
| |
| switch( method ) |
| { |
| case CV_COMP_CHISQR: |
| for( i = 0; i < total; i++ ) |
| { |
| double a = ptr1[i] - ptr2[i]; |
| double b = ptr1[i] + ptr2[i]; |
| if( fabs(b) > DBL_EPSILON ) |
| result += a*a/b; |
| } |
| break; |
| case CV_COMP_CORREL: |
| { |
| double s1 = 0, s11 = 0; |
| double s2 = 0, s22 = 0; |
| double s12 = 0; |
| double num, denom2, scale = 1./total; |
| |
| for( i = 0; i < total; i++ ) |
| { |
| double a = ptr1[i]; |
| double b = ptr2[i]; |
| |
| s12 += a*b; |
| s1 += a; |
| s11 += a*a; |
| s2 += b; |
| s22 += b*b; |
| } |
| |
| num = s12 - s1*s2*scale; |
| denom2 = (s11 - s1*s1*scale)*(s22 - s2*s2*scale); |
| result = fabs(denom2) > DBL_EPSILON ? num/sqrt(denom2) : 1; |
| } |
| break; |
| case CV_COMP_INTERSECT: |
| for( i = 0; i < total; i++ ) |
| { |
| float a = ptr1[i]; |
| float b = ptr2[i]; |
| if( a <= b ) |
| result += a; |
| else |
| result += b; |
| } |
| break; |
| case CV_COMP_BHATTACHARYYA: |
| { |
| double s1 = 0, s2 = 0; |
| for( i = 0; i < total; i++ ) |
| { |
| double a = ptr1[i]; |
| double b = ptr2[i]; |
| result += sqrt(a*b); |
| s1 += a; |
| s2 += b; |
| } |
| s1 *= s2; |
| s1 = fabs(s1) > FLT_EPSILON ? 1./sqrt(s1) : 1.; |
| result = 1. - result*s1; |
| result = sqrt(MAX(result,0.)); |
| } |
| break; |
| default: |
| CV_ERROR( CV_StsBadArg, "Unknown comparison method" ); |
| } |
| } |
| else |
| { |
| CvSparseMat* mat1 = (CvSparseMat*)(hist1->bins); |
| CvSparseMat* mat2 = (CvSparseMat*)(hist2->bins); |
| CvSparseMatIterator iterator; |
| CvSparseNode *node1, *node2; |
| |
| if( mat1->heap->active_count > mat2->heap->active_count ) |
| { |
| CvSparseMat* t; |
| CV_SWAP( mat1, mat2, t ); |
| } |
| |
| switch( method ) |
| { |
| case CV_COMP_CHISQR: |
| for( node1 = cvInitSparseMatIterator( mat1, &iterator ); |
| node1 != 0; node1 = cvGetNextSparseNode( &iterator )) |
| { |
| double v1 = *(float*)CV_NODE_VAL(mat1,node1); |
| uchar* node2_data = cvPtrND( mat2, CV_NODE_IDX(mat1,node1), 0, 0, &node1->hashval ); |
| if( !node2_data ) |
| result += v1; |
| else |
| { |
| double v2 = *(float*)node2_data; |
| double a = v1 - v2; |
| double b = v1 + v2; |
| if( fabs(b) > DBL_EPSILON ) |
| result += a*a/b; |
| } |
| } |
| |
| for( node2 = cvInitSparseMatIterator( mat2, &iterator ); |
| node2 != 0; node2 = cvGetNextSparseNode( &iterator )) |
| { |
| double v2 = *(float*)CV_NODE_VAL(mat2,node2); |
| if( !cvPtrND( mat1, CV_NODE_IDX(mat2,node2), 0, 0, &node2->hashval )) |
| result += v2; |
| } |
| break; |
| case CV_COMP_CORREL: |
| { |
| double s1 = 0, s11 = 0; |
| double s2 = 0, s22 = 0; |
| double s12 = 0; |
| double num, denom2, scale = 1./total; |
| |
| for( node1 = cvInitSparseMatIterator( mat1, &iterator ); |
| node1 != 0; node1 = cvGetNextSparseNode( &iterator )) |
| { |
| double v1 = *(float*)CV_NODE_VAL(mat1,node1); |
| uchar* node2_data = cvPtrND( mat2, CV_NODE_IDX(mat1,node1), |
| 0, 0, &node1->hashval ); |
| if( node2_data ) |
| { |
| double v2 = *(float*)node2_data; |
| s12 += v1*v2; |
| } |
| s1 += v1; |
| s11 += v1*v1; |
| } |
| |
| for( node2 = cvInitSparseMatIterator( mat2, &iterator ); |
| node2 != 0; node2 = cvGetNextSparseNode( &iterator )) |
| { |
| double v2 = *(float*)CV_NODE_VAL(mat2,node2); |
| s2 += v2; |
| s22 += v2*v2; |
| } |
| |
| num = s12 - s1*s2*scale; |
| denom2 = (s11 - s1*s1*scale)*(s22 - s2*s2*scale); |
| result = fabs(denom2) > DBL_EPSILON ? num/sqrt(denom2) : 1; |
| } |
| break; |
| case CV_COMP_INTERSECT: |
| { |
| for( node1 = cvInitSparseMatIterator( mat1, &iterator ); |
| node1 != 0; node1 = cvGetNextSparseNode( &iterator )) |
| { |
| float v1 = *(float*)CV_NODE_VAL(mat1,node1); |
| uchar* node2_data = cvPtrND( mat2, CV_NODE_IDX(mat1,node1), |
| 0, 0, &node1->hashval ); |
| if( node2_data ) |
| { |
| float v2 = *(float*)node2_data; |
| if( v1 <= v2 ) |
| result += v1; |
| else |
| result += v2; |
| } |
| } |
| } |
| break; |
| case CV_COMP_BHATTACHARYYA: |
| { |
| double s1 = 0, s2 = 0; |
| |
| for( node1 = cvInitSparseMatIterator( mat1, &iterator ); |
| node1 != 0; node1 = cvGetNextSparseNode( &iterator )) |
| { |
| double v1 = *(float*)CV_NODE_VAL(mat1,node1); |
| uchar* node2_data = cvPtrND( mat2, CV_NODE_IDX(mat1,node1), |
| 0, 0, &node1->hashval ); |
| s1 += v1; |
| if( node2_data ) |
| { |
| double v2 = *(float*)node2_data; |
| result += sqrt(v1 * v2); |
| } |
| } |
| |
| for( node1 = cvInitSparseMatIterator( mat2, &iterator ); |
| node1 != 0; node1 = cvGetNextSparseNode( &iterator )) |
| { |
| double v2 = *(float*)CV_NODE_VAL(mat2,node1); |
| s2 += v2; |
| } |
| |
| s1 *= s2; |
| s1 = fabs(s1) > FLT_EPSILON ? 1./sqrt(s1) : 1.; |
| result = 1. - result*s1; |
| result = sqrt(MAX(result,0.)); |
| } |
| break; |
| default: |
| CV_ERROR( CV_StsBadArg, "Unknown comparison method" ); |
| } |
| } |
| |
| _result = result; |
| |
| __END__; |
| |
| return _result; |
| } |
| |
| // copies one histogram to another |
| CV_IMPL void |
| cvCopyHist( const CvHistogram* src, CvHistogram** _dst ) |
| { |
| CV_FUNCNAME( "cvCopyHist" ); |
| |
| __BEGIN__; |
| |
| int eq = 0; |
| int is_sparse; |
| int i, dims1, dims2; |
| int size1[CV_MAX_DIM], size2[CV_MAX_DIM], total = 1; |
| float* ranges[CV_MAX_DIM]; |
| float** thresh = 0; |
| CvHistogram* dst; |
| |
| if( !_dst ) |
| CV_ERROR( CV_StsNullPtr, "Destination double pointer is NULL" ); |
| |
| dst = *_dst; |
| |
| if( !CV_IS_HIST(src) || (dst && !CV_IS_HIST(dst)) ) |
| CV_ERROR( CV_StsBadArg, "Invalid histogram header[s]" ); |
| |
| is_sparse = CV_IS_SPARSE_MAT(src->bins); |
| CV_CALL( dims1 = cvGetDims( src->bins, size1 )); |
| for( i = 0; i < dims1; i++ ) |
| total *= size1[i]; |
| |
| if( dst && is_sparse == CV_IS_SPARSE_MAT(dst->bins)) |
| { |
| CV_CALL( dims2 = cvGetDims( dst->bins, size2 )); |
| |
| if( dims1 == dims2 ) |
| { |
| for( i = 0; i < dims1; i++ ) |
| if( size1[i] != size2[i] ) |
| break; |
| } |
| |
| eq = i == dims1; |
| } |
| |
| if( !eq ) |
| { |
| cvReleaseHist( _dst ); |
| CV_CALL( dst = cvCreateHist( dims1, size1, |
| !is_sparse ? CV_HIST_ARRAY : CV_HIST_SPARSE, 0, 0 )); |
| *_dst = dst; |
| } |
| |
| if( CV_HIST_HAS_RANGES( src )) |
| { |
| if( CV_IS_UNIFORM_HIST( src )) |
| { |
| for( i = 0; i < dims1; i++ ) |
| ranges[i] = (float*)src->thresh[i]; |
| thresh = ranges; |
| } |
| else |
| thresh = src->thresh2; |
| CV_CALL( cvSetHistBinRanges( dst, thresh, CV_IS_UNIFORM_HIST(src))); |
| } |
| |
| CV_CALL( cvCopy( src->bins, dst->bins )); |
| |
| __END__; |
| } |
| |
| |
| // Sets a value range for every histogram bin |
| CV_IMPL void |
| cvSetHistBinRanges( CvHistogram* hist, float** ranges, int uniform ) |
| { |
| CV_FUNCNAME( "cvSetHistBinRanges" ); |
| |
| __BEGIN__; |
| |
| int dims, size[CV_MAX_DIM], total = 0; |
| int i, j; |
| |
| if( !ranges ) |
| CV_ERROR( CV_StsNullPtr, "NULL ranges pointer" ); |
| |
| if( !CV_IS_HIST(hist) ) |
| CV_ERROR( CV_StsBadArg, "Invalid histogram header" ); |
| |
| CV_CALL( dims = cvGetDims( hist->bins, size )); |
| for( i = 0; i < dims; i++ ) |
| total += size[i]+1; |
| |
| if( uniform ) |
| { |
| for( i = 0; i < dims; i++ ) |
| { |
| if( !ranges[i] ) |
| CV_ERROR( CV_StsNullPtr, "One of <ranges> elements is NULL" ); |
| hist->thresh[i][0] = ranges[i][0]; |
| hist->thresh[i][1] = ranges[i][1]; |
| } |
| |
| hist->type |= CV_HIST_UNIFORM_FLAG + CV_HIST_RANGES_FLAG; |
| } |
| else |
| { |
| float* dim_ranges; |
| |
| if( !hist->thresh2 ) |
| { |
| CV_CALL( hist->thresh2 = (float**)cvAlloc( |
| dims*sizeof(hist->thresh2[0])+ |
| total*sizeof(hist->thresh2[0][0]))); |
| } |
| dim_ranges = (float*)(hist->thresh2 + dims); |
| |
| for( i = 0; i < dims; i++ ) |
| { |
| float val0 = -FLT_MAX; |
| |
| if( !ranges[i] ) |
| CV_ERROR( CV_StsNullPtr, "One of <ranges> elements is NULL" ); |
| |
| for( j = 0; j <= size[i]; j++ ) |
| { |
| float val = ranges[i][j]; |
| if( val <= val0 ) |
| CV_ERROR(CV_StsOutOfRange, "Bin ranges should go in ascenting order"); |
| val0 = dim_ranges[j] = val; |
| } |
| |
| hist->thresh2[i] = dim_ranges; |
| dim_ranges += size[i] + 1; |
| } |
| |
| hist->type |= CV_HIST_RANGES_FLAG; |
| hist->type &= ~CV_HIST_UNIFORM_FLAG; |
| } |
| |
| __END__; |
| } |
| |
| |
| #define ICV_HIST_DUMMY_IDX (INT_MIN/3) |
| |
| static CvStatus |
| icvCalcHistLookupTables8u( const CvHistogram* hist, int dims, int* size, int* tab ) |
| { |
| const int lo = 0, hi = 256; |
| int is_sparse = CV_IS_SPARSE_HIST( hist ); |
| int have_range = CV_HIST_HAS_RANGES(hist); |
| int i, j; |
| |
| if( !have_range || CV_IS_UNIFORM_HIST(hist)) |
| { |
| for( i = 0; i < dims; i++ ) |
| { |
| double a = have_range ? hist->thresh[i][0] : 0; |
| double b = have_range ? hist->thresh[i][1] : 256; |
| int sz = size[i]; |
| double scale = sz/(b - a); |
| int step = 1; |
| |
| if( !is_sparse ) |
| step = ((CvMatND*)(hist->bins))->dim[i].step/sizeof(float); |
| |
| for( j = lo; j < hi; j++ ) |
| { |
| int idx = cvFloor((j - a)*scale); |
| if( (unsigned)idx < (unsigned)sz ) |
| idx *= step; |
| else |
| idx = ICV_HIST_DUMMY_IDX; |
| |
| tab[i*(hi - lo) + j - lo] = idx; |
| } |
| } |
| } |
| else |
| { |
| for( i = 0; i < dims; i++ ) |
| { |
| double limit = hist->thresh2[i][0]; |
| int idx = -1, write_idx = ICV_HIST_DUMMY_IDX, sz = size[i]; |
| int step = 1; |
| |
| if( !is_sparse ) |
| step = ((CvMatND*)(hist->bins))->dim[i].step/sizeof(float); |
| |
| if( limit > hi ) |
| limit = hi; |
| |
| j = lo; |
| for(;;) |
| { |
| for( ; j < limit; j++ ) |
| tab[i*(hi - lo) + j - lo] = write_idx; |
| |
| if( (unsigned)(++idx) < (unsigned)sz ) |
| { |
| limit = hist->thresh2[i][idx+1]; |
| if( limit > hi ) |
| limit = hi; |
| write_idx = idx*step; |
| } |
| else |
| { |
| for( ; j < hi; j++ ) |
| tab[i*(hi - lo) + j - lo] = ICV_HIST_DUMMY_IDX; |
| break; |
| } |
| } |
| } |
| } |
| |
| return CV_OK; |
| } |
| |
| |
| /***************************** C A L C H I S T O G R A M *************************/ |
| |
| // Calculates histogram for one or more 8u arrays |
| static CvStatus CV_STDCALL |
| icvCalcHist_8u_C1R( uchar** img, int step, uchar* mask, int maskStep, |
| CvSize size, CvHistogram* hist ) |
| { |
| int* tab; |
| int is_sparse = CV_IS_SPARSE_HIST(hist); |
| int dims, histsize[CV_MAX_DIM]; |
| int i, x; |
| CvStatus status; |
| |
| dims = cvGetDims( hist->bins, histsize ); |
| |
| tab = (int*)cvStackAlloc( dims*256*sizeof(int)); |
| status = icvCalcHistLookupTables8u( hist, dims, histsize, tab ); |
| |
| if( status < 0 ) |
| return status; |
| |
| if( !is_sparse ) |
| { |
| int total = 1; |
| int* bins = ((CvMatND*)(hist->bins))->data.i; |
| |
| for( i = 0; i < dims; i++ ) |
| total *= histsize[i]; |
| |
| if( dims <= 3 && total >= -ICV_HIST_DUMMY_IDX ) |
| return CV_BADSIZE_ERR; // too big histogram |
| |
| switch( dims ) |
| { |
| case 1: |
| { |
| int tab1d[256]; |
| memset( tab1d, 0, sizeof(tab1d)); |
| |
| for( ; size.height--; img[0] += step ) |
| { |
| uchar* ptr = img[0]; |
| if( !mask ) |
| { |
| for( x = 0; x <= size.width - 4; x += 4 ) |
| { |
| int v0 = ptr[x]; |
| int v1 = ptr[x+1]; |
| |
| tab1d[v0]++; |
| tab1d[v1]++; |
| |
| v0 = ptr[x+2]; |
| v1 = ptr[x+3]; |
| |
| tab1d[v0]++; |
| tab1d[v1]++; |
| } |
| |
| for( ; x < size.width; x++ ) |
| tab1d[ptr[x]]++; |
| } |
| else |
| { |
| for( x = 0; x < size.width; x++ ) |
| if( mask[x] ) |
| tab1d[ptr[x]]++; |
| mask += maskStep; |
| } |
| } |
| |
| for( i = 0; i < 256; i++ ) |
| { |
| int idx = tab[i]; |
| if( idx >= 0 ) |
| bins[idx] += tab1d[i]; |
| } |
| } |
| break; |
| case 2: |
| for( ; size.height--; img[0] += step, img[1] += step ) |
| { |
| uchar* ptr0 = img[0]; |
| uchar* ptr1 = img[1]; |
| if( !mask ) |
| { |
| for( x = 0; x < size.width; x++ ) |
| { |
| int v0 = ptr0[x]; |
| int v1 = ptr1[x]; |
| int idx = tab[v0] + tab[256+v1]; |
| |
| if( idx >= 0 ) |
| bins[idx]++; |
| } |
| } |
| else |
| { |
| for( x = 0; x < size.width; x++ ) |
| { |
| if( mask[x] ) |
| { |
| int v0 = ptr0[x]; |
| int v1 = ptr1[x]; |
| |
| int idx = tab[v0] + tab[256+v1]; |
| |
| if( idx >= 0 ) |
| bins[idx]++; |
| } |
| } |
| mask += maskStep; |
| } |
| } |
| break; |
| case 3: |
| for( ; size.height--; img[0] += step, img[1] += step, img[2] += step ) |
| { |
| uchar* ptr0 = img[0]; |
| uchar* ptr1 = img[1]; |
| uchar* ptr2 = img[2]; |
| if( !mask ) |
| { |
| for( x = 0; x < size.width; x++ ) |
| { |
| int v0 = ptr0[x]; |
| int v1 = ptr1[x]; |
| int v2 = ptr2[x]; |
| int idx = tab[v0] + tab[256+v1] + tab[512+v2]; |
| |
| if( idx >= 0 ) |
| bins[idx]++; |
| } |
| } |
| else |
| { |
| for( x = 0; x < size.width; x++ ) |
| { |
| if( mask[x] ) |
| { |
| int v0 = ptr0[x]; |
| int v1 = ptr1[x]; |
| int v2 = ptr2[x]; |
| int idx = tab[v0] + tab[256+v1] + tab[512+v2]; |
| |
| if( idx >= 0 ) |
| bins[idx]++; |
| } |
| } |
| mask += maskStep; |
| } |
| } |
| break; |
| default: |
| for( ; size.height--; ) |
| { |
| if( !mask ) |
| { |
| for( x = 0; x < size.width; x++ ) |
| { |
| int* binptr = bins; |
| for( i = 0; i < dims; i++ ) |
| { |
| int idx = tab[i*256 + img[i][x]]; |
| if( idx < 0 ) |
| break; |
| binptr += idx; |
| } |
| if( i == dims ) |
| binptr[0]++; |
| } |
| } |
| else |
| { |
| for( x = 0; x < size.width; x++ ) |
| { |
| if( mask[x] ) |
| { |
| int* binptr = bins; |
| for( i = 0; i < dims; i++ ) |
| { |
| int idx = tab[i*256 + img[i][x]]; |
| if( idx < 0 ) |
| break; |
| binptr += idx; |
| } |
| if( i == dims ) |
| binptr[0]++; |
| } |
| } |
| mask += maskStep; |
| } |
| |
| for( i = 0; i < dims; i++ ) |
| img[i] += step; |
| } |
| } |
| } |
| else |
| { |
| CvSparseMat* mat = (CvSparseMat*)(hist->bins); |
| int node_idx[CV_MAX_DIM]; |
| |
| for( ; size.height--; ) |
| { |
| if( !mask ) |
| { |
| for( x = 0; x < size.width; x++ ) |
| { |
| for( i = 0; i < dims; i++ ) |
| { |
| int idx = tab[i*256 + img[i][x]]; |
| if( idx < 0 ) |
| break; |
| node_idx[i] = idx; |
| } |
| if( i == dims ) |
| { |
| int* bin = (int*)cvPtrND( mat, node_idx, 0, 1 ); |
| bin[0]++; |
| } |
| } |
| } |
| else |
| { |
| for( x = 0; x < size.width; x++ ) |
| { |
| if( mask[x] ) |
| { |
| for( i = 0; i < dims; i++ ) |
| { |
| int idx = tab[i*256 + img[i][x]]; |
| if( idx < 0 ) |
| break; |
| node_idx[i] = idx; |
| } |
| if( i == dims ) |
| { |
| int* bin = (int*)cvPtrND( mat, node_idx, 0, 1, 0 ); |
| bin[0]++; |
| } |
| } |
| } |
| mask += maskStep; |
| } |
| |
| for( i = 0; i < dims; i++ ) |
| img[i] += step; |
| } |
| } |
| |
| return CV_OK; |
| } |
| |
| |
| // Calculates histogram for one or more 32f arrays |
| static CvStatus CV_STDCALL |
| icvCalcHist_32f_C1R( float** img, int step, uchar* mask, int maskStep, |
| CvSize size, CvHistogram* hist ) |
| { |
| int is_sparse = CV_IS_SPARSE_HIST(hist); |
| int uniform = CV_IS_UNIFORM_HIST(hist); |
| int dims, histsize[CV_MAX_DIM]; |
| double uni_range[CV_MAX_DIM][2]; |
| int i, x; |
| |
| dims = cvGetDims( hist->bins, histsize ); |
| step /= sizeof(img[0][0]); |
| |
| if( uniform ) |
| { |
| for( i = 0; i < dims; i++ ) |
| { |
| double t = histsize[i]/((double)hist->thresh[i][1] - hist->thresh[i][0]); |
| uni_range[i][0] = t; |
| uni_range[i][1] = -t*hist->thresh[i][0]; |
| } |
| } |
| |
| if( !is_sparse ) |
| { |
| CvMatND* mat = (CvMatND*)(hist->bins); |
| int* bins = mat->data.i; |
| |
| if( uniform ) |
| { |
| switch( dims ) |
| { |
| case 1: |
| { |
| double a = uni_range[0][0], b = uni_range[0][1]; |
| int sz = histsize[0]; |
| |
| for( ; size.height--; img[0] += step ) |
| { |
| float* ptr = img[0]; |
| |
| if( !mask ) |
| { |
| for( x = 0; x <= size.width - 4; x += 4 ) |
| { |
| int v0 = cvFloor(ptr[x]*a + b); |
| int v1 = cvFloor(ptr[x+1]*a + b); |
| |
| if( (unsigned)v0 < (unsigned)sz ) |
| bins[v0]++; |
| if( (unsigned)v1 < (unsigned)sz ) |
| bins[v1]++; |
| |
| v0 = cvFloor(ptr[x+2]*a + b); |
| v1 = cvFloor(ptr[x+3]*a + b); |
| |
| if( (unsigned)v0 < (unsigned)sz ) |
| bins[v0]++; |
| if( (unsigned)v1 < (unsigned)sz ) |
| bins[v1]++; |
| } |
| |
| for( ; x < size.width; x++ ) |
| { |
| int v0 = cvFloor(ptr[x]*a + b); |
| if( (unsigned)v0 < (unsigned)sz ) |
| bins[v0]++; |
| } |
| } |
| else |
| { |
| for( x = 0; x < size.width; x++ ) |
| if( mask[x] ) |
| { |
| int v0 = cvFloor(ptr[x]*a + b); |
| if( (unsigned)v0 < (unsigned)sz ) |
| bins[v0]++; |
| } |
| mask += maskStep; |
| } |
| } |
| } |
| break; |
| case 2: |
| { |
| double a0 = uni_range[0][0], b0 = uni_range[0][1]; |
| double a1 = uni_range[1][0], b1 = uni_range[1][1]; |
| int sz0 = histsize[0], sz1 = histsize[1]; |
| int step0 = ((CvMatND*)(hist->bins))->dim[0].step/sizeof(float); |
| |
| for( ; size.height--; img[0] += step, img[1] += step ) |
| { |
| float* ptr0 = img[0]; |
| float* ptr1 = img[1]; |
| |
| if( !mask ) |
| { |
| for( x = 0; x < size.width; x++ ) |
| { |
| int v0 = cvFloor( ptr0[x]*a0 + b0 ); |
| int v1 = cvFloor( ptr1[x]*a1 + b1 ); |
| |
| if( (unsigned)v0 < (unsigned)sz0 && |
| (unsigned)v1 < (unsigned)sz1 ) |
| bins[v0*step0 + v1]++; |
| } |
| } |
| else |
| { |
| for( x = 0; x < size.width; x++ ) |
| { |
| if( mask[x] ) |
| { |
| int v0 = cvFloor( ptr0[x]*a0 + b0 ); |
| int v1 = cvFloor( ptr1[x]*a1 + b1 ); |
| |
| if( (unsigned)v0 < (unsigned)sz0 && |
| (unsigned)v1 < (unsigned)sz1 ) |
| bins[v0*step0 + v1]++; |
| } |
| } |
| mask += maskStep; |
| } |
| } |
| } |
| break; |
| default: |
| for( ; size.height--; ) |
| { |
| if( !mask ) |
| { |
| for( x = 0; x < size.width; x++ ) |
| { |
| int* binptr = bins; |
| for( i = 0; i < dims; i++ ) |
| { |
| int idx = cvFloor((double)img[i][x]*uni_range[i][0] |
| + uni_range[i][1]); |
| if( (unsigned)idx >= (unsigned)histsize[i] ) |
| break; |
| binptr += idx*(mat->dim[i].step/sizeof(float)); |
| } |
| if( i == dims ) |
| binptr[0]++; |
| } |
| } |
| else |
| { |
| for( x = 0; x < size.width; x++ ) |
| { |
| if( mask[x] ) |
| { |
| int* binptr = bins; |
| for( i = 0; i < dims; i++ ) |
| { |
| int idx = cvFloor((double)img[i][x]*uni_range[i][0] |
| + uni_range[i][1]); |
| if( (unsigned)idx >= (unsigned)histsize[i] ) |
| break; |
| binptr += idx*(mat->dim[i].step/sizeof(float)); |
| } |
| if( i == dims ) |
| binptr[0]++; |
| } |
| } |
| mask += maskStep; |
| } |
| |
| for( i = 0; i < dims; i++ ) |
| img[i] += step; |
| } |
| } |
| } |
| else |
| { |
| for( ; size.height--; ) |
| { |
| for( x = 0; x < size.width; x++ ) |
| { |
| if( !mask || mask[x] ) |
| { |
| int* binptr = bins; |
| for( i = 0; i < dims; i++ ) |
| { |
| float v = img[i][x]; |
| float* thresh = hist->thresh2[i]; |
| int idx = -1, sz = histsize[i]; |
| |
| while( v >= thresh[idx+1] && ++idx < sz ) |
| /* nop */; |
| |
| if( (unsigned)idx >= (unsigned)sz ) |
| break; |
| |
| binptr += idx*(mat->dim[i].step/sizeof(float)); |
| } |
| if( i == dims ) |
| binptr[0]++; |
| } |
| } |
| |
| for( i = 0; i < dims; i++ ) |
| img[i] += step; |
| if( mask ) |
| mask += maskStep; |
| } |
| } |
| } |
| else |
| { |
| CvSparseMat* mat = (CvSparseMat*)(hist->bins); |
| int node_idx[CV_MAX_DIM]; |
| |
| for( ; size.height--; ) |
| { |
| if( uniform ) |
| { |
| for( x = 0; x < size.width; x++ ) |
| { |
| if( !mask || mask[x] ) |
| { |
| for( i = 0; i < dims; i++ ) |
| { |
| int idx = cvFloor(img[i][x]*uni_range[i][0] |
| + uni_range[i][1]); |
| if( (unsigned)idx >= (unsigned)histsize[i] ) |
| break; |
| node_idx[i] = idx; |
| } |
| if( i == dims ) |
| { |
| int* bin = (int*)cvPtrND( mat, node_idx, 0, 1, 0 ); |
| bin[0]++; |
| } |
| } |
| } |
| } |
| else |
| { |
| for( x = 0; x < size.width; x++ ) |
| { |
| if( !mask || mask[x] ) |
| { |
| for( i = 0; i < dims; i++ ) |
| { |
| float v = img[i][x]; |
| float* thresh = hist->thresh2[i]; |
| int idx = -1, sz = histsize[i]; |
| |
| while( v >= thresh[idx+1] && ++idx < sz ) |
| /* nop */; |
| |
| if( (unsigned)idx >= (unsigned)sz ) |
| break; |
| |
| node_idx[i] = idx; |
| } |
| if( i == dims ) |
| { |
| int* bin = (int*)cvPtrND( mat, node_idx, 0, 1, 0 ); |
| bin[0]++; |
| } |
| } |
| } |
| } |
| |
| for( i = 0; i < dims; i++ ) |
| img[i] += step; |
| |
| if( mask ) |
| mask += maskStep; |
| } |
| } |
| |
| return CV_OK; |
| } |
| |
| |
| CV_IMPL void |
| cvCalcArrHist( CvArr** img, CvHistogram* hist, |
| int do_not_clear, const CvArr* mask ) |
| { |
| CV_FUNCNAME( "cvCalcHist" ); |
| |
| __BEGIN__; |
| |
| uchar* ptr[CV_MAX_DIM]; |
| uchar* maskptr = 0; |
| int maskstep = 0, step = 0; |
| int i, dims; |
| int cont_flag = -1; |
| CvMat stub0, *mat0 = 0; |
| CvMatND dense; |
| CvSize size; |
| |
| if( !CV_IS_HIST(hist)) |
| CV_ERROR( CV_StsBadArg, "Bad histogram pointer" ); |
| |
| if( !img ) |
| CV_ERROR( CV_StsNullPtr, "Null double array pointer" ); |
| |
| CV_CALL( dims = cvGetDims( hist->bins )); |
| |
| for( i = 0; i < dims; i++ ) |
| { |
| CvMat stub, *mat = (CvMat*)img[i]; |
| CV_CALL( mat = cvGetMat( mat, i == 0 ? &stub0 : &stub, 0, 1 )); |
| |
| if( CV_MAT_CN( mat->type ) != 1 ) |
| CV_ERROR( CV_BadNumChannels, "Only 1-channel arrays are allowed here" ); |
| |
| if( i == 0 ) |
| { |
| mat0 = mat; |
| step = mat0->step; |
| } |
| else |
| { |
| if( !CV_ARE_SIZES_EQ( mat0, mat )) |
| CV_ERROR( CV_StsUnmatchedSizes, "Not all the planes have equal sizes" ); |
| |
| if( mat0->step != mat->step ) |
| CV_ERROR( CV_StsUnmatchedSizes, "Not all the planes have equal steps" ); |
| |
| if( !CV_ARE_TYPES_EQ( mat0, mat )) |
| CV_ERROR( CV_StsUnmatchedFormats, "Not all the planes have equal types" ); |
| } |
| |
| cont_flag &= mat->type; |
| ptr[i] = mat->data.ptr; |
| } |
| |
| if( mask ) |
| { |
| CvMat stub, *mat = (CvMat*)mask; |
| CV_CALL( mat = cvGetMat( mat, &stub, 0, 1 )); |
| |
| if( !CV_IS_MASK_ARR(mat)) |
| CV_ERROR( CV_StsBadMask, "Bad mask array" ); |
| |
| if( !CV_ARE_SIZES_EQ( mat0, mat )) |
| CV_ERROR( CV_StsUnmatchedSizes, |
| "Mask size does not match to other arrays\' size" ); |
| maskptr = mat->data.ptr; |
| maskstep = mat->step; |
| cont_flag &= mat->type; |
| } |
| |
| size = cvGetMatSize(mat0); |
| if( CV_IS_MAT_CONT( cont_flag )) |
| { |
| size.width *= size.height; |
| size.height = 1; |
| maskstep = step = CV_STUB_STEP; |
| } |
| |
| if( !CV_IS_SPARSE_HIST(hist)) |
| { |
| dense = *(CvMatND*)hist->bins; |
| dense.type = (dense.type & ~CV_MAT_TYPE_MASK) | CV_32SC1; |
| } |
| |
| if( !do_not_clear ) |
| { |
| CV_CALL( cvZero( hist->bins )); |
| } |
| else if( !CV_IS_SPARSE_HIST(hist)) |
| { |
| CV_CALL( cvConvert( (CvMatND*)hist->bins, &dense )); |
| } |
| else |
| { |
| CvSparseMat* mat = (CvSparseMat*)(hist->bins); |
| CvSparseMatIterator iterator; |
| CvSparseNode* node; |
| |
| for( node = cvInitSparseMatIterator( mat, &iterator ); |
| node != 0; node = cvGetNextSparseNode( &iterator )) |
| { |
| Cv32suf* val = (Cv32suf*)CV_NODE_VAL( mat, node ); |
| val->i = cvRound( val->f ); |
| } |
| } |
| |
| if( CV_MAT_DEPTH(mat0->type) > CV_8S && !CV_HIST_HAS_RANGES(hist)) |
| CV_ERROR( CV_StsBadArg, "histogram ranges must be set (via cvSetHistBinRanges) " |
| "before calling the function" ); |
| |
| switch( CV_MAT_DEPTH(mat0->type) ) |
| { |
| case CV_8U: |
| IPPI_CALL( icvCalcHist_8u_C1R( ptr, step, maskptr, maskstep, size, hist )); |
| break; |
| case CV_32F: |
| { |
| union { uchar** ptr; float** fl; } v; |
| v.ptr = ptr; |
| IPPI_CALL( icvCalcHist_32f_C1R( v.fl, step, maskptr, maskstep, size, hist )); |
| } |
| break; |
| default: |
| CV_ERROR( CV_StsUnsupportedFormat, "Unsupported array type" ); |
| } |
| |
| if( !CV_IS_SPARSE_HIST(hist)) |
| { |
| CV_CALL( cvConvert( &dense, (CvMatND*)hist->bins )); |
| } |
| else |
| { |
| CvSparseMat* mat = (CvSparseMat*)(hist->bins); |
| CvSparseMatIterator iterator; |
| CvSparseNode* node; |
| |
| for( node = cvInitSparseMatIterator( mat, &iterator ); |
| node != 0; node = cvGetNextSparseNode( &iterator )) |
| { |
| Cv32suf* val = (Cv32suf*)CV_NODE_VAL( mat, node ); |
| val->f = (float)val->i; |
| } |
| } |
| |
| __END__; |
| } |
| |
| |
| /***************************** B A C K P R O J E C T *****************************/ |
| |
| // Calculates back project for one or more 8u arrays |
| static CvStatus CV_STDCALL |
| icvCalcBackProject_8u_C1R( uchar** img, int step, uchar* dst, int dstStep, |
| CvSize size, const CvHistogram* hist ) |
| { |
| const int small_hist_size = 1<<12; |
| int* tab = 0; |
| int is_sparse = CV_IS_SPARSE_HIST(hist); |
| int dims, histsize[CV_MAX_DIM]; |
| int i, x; |
| CvStatus status; |
| |
| dims = cvGetDims( hist->bins, histsize ); |
| |
| tab = (int*)cvStackAlloc( dims*256*sizeof(int)); |
| status = icvCalcHistLookupTables8u( hist, dims, histsize, tab ); |
| if( status < 0 ) |
| return status; |
| |
| if( !is_sparse ) |
| { |
| int total = 1; |
| CvMatND* mat = (CvMatND*)(hist->bins); |
| float* bins = mat->data.fl; |
| uchar* buffer = 0; |
| |
| for( i = 0; i < dims; i++ ) |
| total *= histsize[i]; |
| |
| if( dims <= 3 && total >= -ICV_HIST_DUMMY_IDX ) |
| return CV_BADSIZE_ERR; // too big histogram |
| |
| if( dims > 1 && total <= small_hist_size && CV_IS_MAT_CONT(mat->type)) |
| { |
| buffer = (uchar*)cvAlloc(total); |
| if( !buffer ) |
| return CV_OUTOFMEM_ERR; |
| for( i = 0; i < total; i++ ) |
| { |
| int v = cvRound(bins[i]); |
| buffer[i] = CV_CAST_8U(v); |
| } |
| } |
| |
| switch( dims ) |
| { |
| case 1: |
| { |
| uchar tab1d[256]; |
| for( i = 0; i < 256; i++ ) |
| { |
| int idx = tab[i]; |
| if( idx >= 0 ) |
| { |
| int v = cvRound(bins[idx]); |
| tab1d[i] = CV_CAST_8U(v); |
| } |
| else |
| tab1d[i] = 0; |
| } |
| |
| for( ; size.height--; img[0] += step, dst += dstStep ) |
| { |
| uchar* ptr = img[0]; |
| for( x = 0; x <= size.width - 4; x += 4 ) |
| { |
| uchar v0 = tab1d[ptr[x]]; |
| uchar v1 = tab1d[ptr[x+1]]; |
| |
| dst[x] = v0; |
| dst[x+1] = v1; |
| |
| v0 = tab1d[ptr[x+2]]; |
| v1 = tab1d[ptr[x+3]]; |
| |
| dst[x+2] = v0; |
| dst[x+3] = v1; |
| } |
| |
| for( ; x < size.width; x++ ) |
| dst[x] = tab1d[ptr[x]]; |
| } |
| } |
| break; |
| case 2: |
| for( ; size.height--; img[0] += step, img[1] += step, dst += dstStep ) |
| { |
| uchar* ptr0 = img[0]; |
| uchar* ptr1 = img[1]; |
| |
| if( buffer ) |
| { |
| for( x = 0; x < size.width; x++ ) |
| { |
| int v0 = ptr0[x]; |
| int v1 = ptr1[x]; |
| int idx = tab[v0] + tab[256+v1]; |
| int v = 0; |
| |
| if( idx >= 0 ) |
| v = buffer[idx]; |
| |
| dst[x] = (uchar)v; |
| } |
| } |
| else |
| { |
| for( x = 0; x < size.width; x++ ) |
| { |
| int v0 = ptr0[x]; |
| int v1 = ptr1[x]; |
| int idx = tab[v0] + tab[256+v1]; |
| int v = 0; |
| |
| if( idx >= 0 ) |
| { |
| v = cvRound(bins[idx]); |
| v = CV_CAST_8U(v); |
| } |
| |
| dst[x] = (uchar)v; |
| } |
| } |
| } |
| break; |
| case 3: |
| for( ; size.height--; img[0] += step, img[1] += step, |
| img[2] += step, dst += dstStep ) |
| { |
| uchar* ptr0 = img[0]; |
| uchar* ptr1 = img[1]; |
| uchar* ptr2 = img[2]; |
| |
| if( buffer ) |
| { |
| for( x = 0; x < size.width; x++ ) |
| { |
| int v0 = ptr0[x]; |
| int v1 = ptr1[x]; |
| int v2 = ptr2[x]; |
| int idx = tab[v0] + tab[256+v1] + tab[512+v2]; |
| int v = 0; |
| |
| if( idx >= 0 ) |
| v = buffer[idx]; |
| |
| dst[x] = (uchar)v; |
| } |
| } |
| else |
| { |
| for( x = 0; x < size.width; x++ ) |
| { |
| int v0 = ptr0[x]; |
| int v1 = ptr1[x]; |
| int v2 = ptr2[x]; |
| int idx = tab[v0] + tab[256+v1] + tab[512+v2]; |
| int v = 0; |
| |
| if( idx >= 0 ) |
| { |
| v = cvRound(bins[idx]); |
| v = CV_CAST_8U(v); |
| } |
| dst[x] = (uchar)v; |
| } |
| } |
| } |
| break; |
| default: |
| for( ; size.height--; dst += dstStep ) |
| { |
| if( buffer ) |
| { |
| for( x = 0; x < size.width; x++ ) |
| { |
| uchar* binptr = buffer; |
| int v = 0; |
| |
| for( i = 0; i < dims; i++ ) |
| { |
| int idx = tab[i*256 + img[i][x]]; |
| if( idx < 0 ) |
| break; |
| binptr += idx; |
| } |
| |
| if( i == dims ) |
| v = binptr[0]; |
| |
| dst[x] = (uchar)v; |
| } |
| } |
| else |
| { |
| for( x = 0; x < size.width; x++ ) |
| { |
| float* binptr = bins; |
| int v = 0; |
| |
| for( i = 0; i < dims; i++ ) |
| { |
| int idx = tab[i*256 + img[i][x]]; |
| if( idx < 0 ) |
| break; |
| binptr += idx; |
| } |
| |
| if( i == dims ) |
| { |
| v = cvRound( binptr[0] ); |
| v = CV_CAST_8U(v); |
| } |
| |
| dst[x] = (uchar)v; |
| } |
| } |
| |
| for( i = 0; i < dims; i++ ) |
| img[i] += step; |
| } |
| } |
| |
| cvFree( &buffer ); |
| } |
| else |
| { |
| CvSparseMat* mat = (CvSparseMat*)(hist->bins); |
| int node_idx[CV_MAX_DIM]; |
| |
| for( ; size.height--; dst += dstStep ) |
| { |
| for( x = 0; x < size.width; x++ ) |
| { |
| int v = 0; |
| |
| for( i = 0; i < dims; i++ ) |
| { |
| int idx = tab[i*256 + img[i][x]]; |
| if( idx < 0 ) |
| break; |
| node_idx[i] = idx; |
| } |
| if( i == dims ) |
| { |
| float* bin = (float*)cvPtrND( mat, node_idx, 0, 1, 0 ); |
| v = cvRound(bin[0]); |
| v = CV_CAST_8U(v); |
| } |
| |
| dst[x] = (uchar)v; |
| } |
| |
| for( i = 0; i < dims; i++ ) |
| img[i] += step; |
| } |
| } |
| |
| return CV_OK; |
| } |
| |
| |
| // Calculates back project for one or more 32f arrays |
| static CvStatus CV_STDCALL |
| icvCalcBackProject_32f_C1R( float** img, int step, float* dst, int dstStep, |
| CvSize size, const CvHistogram* hist ) |
| { |
| int is_sparse = CV_IS_SPARSE_HIST(hist); |
| int uniform = CV_IS_UNIFORM_HIST(hist); |
| int dims, histsize[CV_MAX_DIM]; |
| double uni_range[CV_MAX_DIM][2]; |
| int i, x; |
| |
| dims = cvGetDims( hist->bins, histsize ); |
| step /= sizeof(img[0][0]); |
| dstStep /= sizeof(dst[0]); |
| |
| if( uniform ) |
| { |
| for( i = 0; i < dims; i++ ) |
| { |
| double t = ((double)histsize[i])/ |
| ((double)hist->thresh[i][1] - hist->thresh[i][0]); |
| uni_range[i][0] = t; |
| uni_range[i][1] = -t*hist->thresh[i][0]; |
| } |
| } |
| |
| if( !is_sparse ) |
| { |
| CvMatND* mat = (CvMatND*)(hist->bins); |
| float* bins = mat->data.fl; |
| |
| if( uniform ) |
| { |
| switch( dims ) |
| { |
| case 1: |
| { |
| double a = uni_range[0][0], b = uni_range[0][1]; |
| int sz = histsize[0]; |
| |
| for( ; size.height--; img[0] += step, dst += dstStep ) |
| { |
| float* ptr = img[0]; |
| |
| for( x = 0; x <= size.width - 4; x += 4 ) |
| { |
| int v0 = cvFloor(ptr[x]*a + b); |
| int v1 = cvFloor(ptr[x+1]*a + b); |
| |
| if( (unsigned)v0 < (unsigned)sz ) |
| dst[x] = bins[v0]; |
| else |
| dst[x] = 0; |
| |
| if( (unsigned)v1 < (unsigned)sz ) |
| dst[x+1] = bins[v1]; |
| else |
| dst[x+1] = 0; |
| |
| v0 = cvFloor(ptr[x+2]*a + b); |
| v1 = cvFloor(ptr[x+3]*a + b); |
| |
| if( (unsigned)v0 < (unsigned)sz ) |
| dst[x+2] = bins[v0]; |
| else |
| dst[x+2] = 0; |
| |
| if( (unsigned)v1 < (unsigned)sz ) |
| dst[x+3] = bins[v1]; |
| else |
| dst[x+3] = 0; |
| } |
| |
| for( ; x < size.width; x++ ) |
| { |
| int v0 = cvFloor(ptr[x]*a + b); |
| |
| if( (unsigned)v0 < (unsigned)sz ) |
| dst[x] = bins[v0]; |
| else |
| dst[x] = 0; |
| } |
| } |
| } |
| break; |
| case 2: |
| { |
| double a0 = uni_range[0][0], b0 = uni_range[0][1]; |
| double a1 = uni_range[1][0], b1 = uni_range[1][1]; |
| int sz0 = histsize[0], sz1 = histsize[1]; |
| int step0 = ((CvMatND*)(hist->bins))->dim[0].step/sizeof(float); |
| |
| for( ; size.height--; img[0] += step, img[1] += step, dst += dstStep ) |
| { |
| float* ptr0 = img[0]; |
| float* ptr1 = img[1]; |
| |
| for( x = 0; x < size.width; x++ ) |
| { |
| int v0 = cvFloor( ptr0[x]*a0 + b0 ); |
| int v1 = cvFloor( ptr1[x]*a1 + b1 ); |
| |
| if( (unsigned)v0 < (unsigned)sz0 && |
| (unsigned)v1 < (unsigned)sz1 ) |
| dst[x] = bins[v0*step0 + v1]; |
| else |
| dst[x] = 0; |
| } |
| } |
| } |
| break; |
| default: |
| for( ; size.height--; dst += dstStep ) |
| { |
| for( x = 0; x < size.width; x++ ) |
| { |
| float* binptr = bins; |
| |
| for( i = 0; i < dims; i++ ) |
| { |
| int idx = cvFloor(img[i][x]*uni_range[i][0] |
| + uni_range[i][1]); |
| if( (unsigned)idx >= (unsigned)histsize[i] ) |
| break; |
| binptr += idx*(mat->dim[i].step/sizeof(float)); |
| } |
| if( i == dims ) |
| dst[x] = binptr[0]; |
| else |
| dst[x] = 0; |
| } |
| } |
| |
| for( i = 0; i < dims; i++ ) |
| img[i] += step; |
| } |
| } |
| else |
| { |
| for( ; size.height--; dst += dstStep ) |
| { |
| for( x = 0; x < size.width; x++ ) |
| { |
| float* binptr = bins; |
| for( i = 0; i < dims; i++ ) |
| { |
| float v = img[i][x]; |
| float* thresh = hist->thresh2[i]; |
| int idx = -1, sz = histsize[i]; |
| |
| while( v >= thresh[idx+1] && ++idx < sz ) |
| /* nop */; |
| |
| if( (unsigned)idx >= (unsigned)sz ) |
| break; |
| |
| binptr += idx*(mat->dim[i].step/sizeof(float)); |
| } |
| if( i == dims ) |
| dst[x] = binptr[0]; |
| else |
| dst[x] = 0; |
| } |
| |
| for( i = 0; i < dims; i++ ) |
| img[i] += step; |
| } |
| } |
| } |
| else |
| { |
| CvSparseMat* mat = (CvSparseMat*)(hist->bins); |
| int node_idx[CV_MAX_DIM]; |
| |
| for( ; size.height--; dst += dstStep ) |
| { |
| if( uniform ) |
| { |
| for( x = 0; x < size.width; x++ ) |
| { |
| for( i = 0; i < dims; i++ ) |
| { |
| int idx = cvFloor(img[i][x]*uni_range[i][0] |
| + uni_range[i][1]); |
| if( (unsigned)idx >= (unsigned)histsize[i] ) |
| break; |
| node_idx[i] = idx; |
| } |
| if( i == dims ) |
| { |
| float* bin = (float*)cvPtrND( mat, node_idx, 0, 1, 0 ); |
| dst[x] = bin[0]; |
| } |
| else |
| dst[x] = 0; |
| } |
| } |
| else |
| { |
| for( x = 0; x < size.width; x++ ) |
| { |
| for( i = 0; i < dims; i++ ) |
| { |
| float v = img[i][x]; |
| float* thresh = hist->thresh2[i]; |
| int idx = -1, sz = histsize[i]; |
| |
| while( v >= thresh[idx+1] && ++idx < sz ) |
| /* nop */; |
| |
| if( (unsigned)idx >= (unsigned)sz ) |
| break; |
| |
| node_idx[i] = idx; |
| } |
| if( i == dims ) |
| { |
| float* bin = (float*)cvPtrND( mat, node_idx, 0, 1, 0 ); |
| dst[x] = bin[0]; |
| } |
| else |
| dst[x] = 0; |
| } |
| } |
| |
| for( i = 0; i < dims; i++ ) |
| img[i] += step; |
| } |
| } |
| |
| return CV_OK; |
| } |
| |
| |
| CV_IMPL void |
| cvCalcArrBackProject( CvArr** img, CvArr* dst, const CvHistogram* hist ) |
| { |
| CV_FUNCNAME( "cvCalcArrBackProject" ); |
| |
| __BEGIN__; |
| |
| uchar* ptr[CV_MAX_DIM]; |
| uchar* dstptr = 0; |
| int dststep = 0, step = 0; |
| int i, dims; |
| int cont_flag = -1; |
| CvMat stub0, *mat0 = 0; |
| CvSize size; |
| |
| if( !CV_IS_HIST(hist)) |
| CV_ERROR( CV_StsBadArg, "Bad histogram pointer" ); |
| |
| if( !img ) |
| CV_ERROR( CV_StsNullPtr, "Null double array pointer" ); |
| |
| CV_CALL( dims = cvGetDims( hist->bins )); |
| |
| for( i = 0; i <= dims; i++ ) |
| { |
| CvMat stub, *mat = (CvMat*)(i < dims ? img[i] : dst); |
| CV_CALL( mat = cvGetMat( mat, i == 0 ? &stub0 : &stub, 0, 1 )); |
| |
| if( CV_MAT_CN( mat->type ) != 1 ) |
| CV_ERROR( CV_BadNumChannels, "Only 1-channel arrays are allowed here" ); |
| |
| if( i == 0 ) |
| { |
| mat0 = mat; |
| step = mat0->step; |
| } |
| else |
| { |
| if( !CV_ARE_SIZES_EQ( mat0, mat )) |
| CV_ERROR( CV_StsUnmatchedSizes, "Not all the planes have equal sizes" ); |
| |
| if( mat0->step != mat->step ) |
| CV_ERROR( CV_StsUnmatchedSizes, "Not all the planes have equal steps" ); |
| |
| if( !CV_ARE_TYPES_EQ( mat0, mat )) |
| CV_ERROR( CV_StsUnmatchedFormats, "Not all the planes have equal types" ); |
| } |
| |
| cont_flag &= mat->type; |
| if( i < dims ) |
| ptr[i] = mat->data.ptr; |
| else |
| { |
| dstptr = mat->data.ptr; |
| dststep = mat->step; |
| } |
| } |
| |
| size = cvGetMatSize(mat0); |
| if( CV_IS_MAT_CONT( cont_flag )) |
| { |
| size.width *= size.height; |
| size.height = 1; |
| dststep = step = CV_STUB_STEP; |
| } |
| |
| if( CV_MAT_DEPTH(mat0->type) > CV_8S && !CV_HIST_HAS_RANGES(hist)) |
| CV_ERROR( CV_StsBadArg, "histogram ranges must be set (via cvSetHistBinRanges) " |
| "before calling the function" ); |
| |
| switch( CV_MAT_DEPTH(mat0->type) ) |
| { |
| case CV_8U: |
| IPPI_CALL( icvCalcBackProject_8u_C1R( ptr, step, dstptr, dststep, size, hist )); |
| break; |
| case CV_32F: |
| { |
| union { uchar** ptr; float** fl; } v; |
| v.ptr = ptr; |
| IPPI_CALL( icvCalcBackProject_32f_C1R( v.fl, step, |
| (float*)dstptr, dststep, size, hist )); |
| } |
| break; |
| default: |
| CV_ERROR( CV_StsUnsupportedFormat, "Unsupported array type" ); |
| } |
| |
| __END__; |
| } |
| |
| |
| ////////////////////// B A C K P R O J E C T P A T C H ///////////////////////// |
| |
| CV_IMPL void |
| cvCalcArrBackProjectPatch( CvArr** arr, CvArr* dst, CvSize patch_size, CvHistogram* hist, |
| int method, double norm_factor ) |
| { |
| CvHistogram* model = 0; |
| |
| CV_FUNCNAME( "cvCalcArrBackProjectPatch" ); |
| |
| __BEGIN__; |
| |
| IplImage imgstub[CV_MAX_DIM], *img[CV_MAX_DIM]; |
| IplROI roi; |
| CvMat dststub, *dstmat; |
| int i, dims; |
| int x, y; |
| CvSize size; |
| |
| if( !CV_IS_HIST(hist)) |
| CV_ERROR( CV_StsBadArg, "Bad histogram pointer" ); |
| |
| if( !arr ) |
| CV_ERROR( CV_StsNullPtr, "Null double array pointer" ); |
| |
| if( norm_factor <= 0 ) |
| CV_ERROR( CV_StsOutOfRange, |
| "Bad normalization factor (set it to 1.0 if unsure)" ); |
| |
| if( patch_size.width <= 0 || patch_size.height <= 0 ) |
| CV_ERROR( CV_StsBadSize, "The patch width and height must be positive" ); |
| |
| CV_CALL( dims = cvGetDims( hist->bins )); |
| CV_CALL( cvCopyHist( hist, &model )); |
| CV_CALL( cvNormalizeHist( hist, norm_factor )); |
| |
| for( i = 0; i < dims; i++ ) |
| { |
| CvMat stub, *mat; |
| CV_CALL( mat = cvGetMat( arr[i], &stub, 0, 0 )); |
| CV_CALL( img[i] = cvGetImage( mat, &imgstub[i] )); |
| img[i]->roi = &roi; |
| } |
| |
| CV_CALL( dstmat = cvGetMat( dst, &dststub, 0, 0 )); |
| if( CV_MAT_TYPE( dstmat->type ) != CV_32FC1 ) |
| CV_ERROR( CV_StsUnsupportedFormat, "Resultant image must have 32fC1 type" ); |
| |
| if( dstmat->cols != img[0]->width - patch_size.width + 1 || |
| dstmat->rows != img[0]->height - patch_size.height + 1 ) |
| CV_ERROR( CV_StsUnmatchedSizes, |
| "The output map must be (W-w+1 x H-h+1), " |
| "where the input images are (W x H) each and the patch is (w x h)" ); |
| |
| size = cvGetMatSize(dstmat); |
| roi.coi = 0; |
| roi.width = patch_size.width; |
| roi.height = patch_size.height; |
| |
| for( y = 0; y < size.height; y++ ) |
| { |
| for( x = 0; x < size.width; x++ ) |
| { |
| double result; |
| |
| roi.xOffset = x; |
| roi.yOffset = y; |
| |
| CV_CALL( cvCalcHist( img, model )); |
| |
| CV_CALL( cvNormalizeHist( model, norm_factor )); |
| CV_CALL( result = cvCompareHist( model, hist, method )); |
| CV_MAT_ELEM( *dstmat, float, y, x ) = (float)result; |
| } |
| } |
| |
| __END__; |
| |
| cvReleaseHist( &model ); |
| } |
| |
| |
| // Calculates Bayes probabilistic histograms |
| CV_IMPL void |
| cvCalcBayesianProb( CvHistogram** src, int count, CvHistogram** dst ) |
| { |
| CV_FUNCNAME( "cvCalcBayesianProb" ); |
| |
| __BEGIN__; |
| |
| int i; |
| |
| if( !src || !dst ) |
| CV_ERROR( CV_StsNullPtr, "NULL histogram array pointer" ); |
| |
| if( count < 2 ) |
| CV_ERROR( CV_StsOutOfRange, "Too small number of histograms" ); |
| |
| for( i = 0; i < count; i++ ) |
| { |
| if( !CV_IS_HIST(src[i]) || !CV_IS_HIST(dst[i]) ) |
| CV_ERROR( CV_StsBadArg, "Invalid histogram header" ); |
| |
| if( !CV_IS_MATND(src[i]->bins) || !CV_IS_MATND(dst[i]->bins) ) |
| CV_ERROR( CV_StsBadArg, "The function supports dense histograms only" ); |
| } |
| |
| cvZero( dst[0]->bins ); |
| // dst[0] = src[0] + ... + src[count-1] |
| for( i = 0; i < count; i++ ) |
| CV_CALL( cvAdd( src[i]->bins, dst[0]->bins, dst[0]->bins )); |
| |
| CV_CALL( cvDiv( 0, dst[0]->bins, dst[0]->bins )); |
| |
| // dst[i] = src[i]*(1/dst[0]) |
| for( i = count - 1; i >= 0; i-- ) |
| CV_CALL( cvMul( src[i]->bins, dst[0]->bins, dst[i]->bins )); |
| |
| __END__; |
| } |
| |
| |
| CV_IMPL void |
| cvCalcProbDensity( const CvHistogram* hist, const CvHistogram* hist_mask, |
| CvHistogram* hist_dens, double scale ) |
| { |
| CV_FUNCNAME( "cvCalcProbDensity" ); |
| |
| __BEGIN__; |
| |
| if( scale <= 0 ) |
| CV_ERROR( CV_StsOutOfRange, "scale must be positive" ); |
| |
| if( !CV_IS_HIST(hist) || !CV_IS_HIST(hist_mask) || !CV_IS_HIST(hist_dens) ) |
| CV_ERROR( CV_StsBadArg, "Invalid histogram pointer[s]" ); |
| |
| { |
| CvArr* arrs[] = { hist->bins, hist_mask->bins, hist_dens->bins }; |
| CvMatND stubs[3]; |
| CvNArrayIterator iterator; |
| |
| CV_CALL( cvInitNArrayIterator( 3, arrs, 0, stubs, &iterator )); |
| |
| if( CV_MAT_TYPE(iterator.hdr[0]->type) != CV_32FC1 ) |
| CV_ERROR( CV_StsUnsupportedFormat, "All histograms must have 32fC1 type" ); |
| |
| do |
| { |
| const float* srcdata = (const float*)(iterator.ptr[0]); |
| const float* maskdata = (const float*)(iterator.ptr[1]); |
| float* dstdata = (float*)(iterator.ptr[2]); |
| int i; |
| |
| for( i = 0; i < iterator.size.width; i++ ) |
| { |
| float s = srcdata[i]; |
| float m = maskdata[i]; |
| if( s > FLT_EPSILON ) |
| if( m <= s ) |
| dstdata[i] = (float)(m*scale/s); |
| else |
| dstdata[i] = (float)scale; |
| else |
| dstdata[i] = (float)0; |
| } |
| } |
| while( cvNextNArraySlice( &iterator )); |
| } |
| |
| __END__; |
| } |
| |
| |
| CV_IMPL void cvEqualizeHist( const CvArr* src, CvArr* dst ) |
| { |
| CvHistogram* hist = 0; |
| CvMat* lut = 0; |
| |
| CV_FUNCNAME( "cvEqualizeHist" ); |
| |
| __BEGIN__; |
| |
| int i, hist_sz = 256; |
| CvSize img_sz; |
| float scale; |
| float* h; |
| int sum = 0; |
| int type; |
| |
| CV_CALL( type = cvGetElemType( src )); |
| if( type != CV_8UC1 ) |
| CV_ERROR( CV_StsUnsupportedFormat, "Only 8uC1 images are supported" ); |
| |
| CV_CALL( hist = cvCreateHist( 1, &hist_sz, CV_HIST_ARRAY )); |
| CV_CALL( lut = cvCreateMat( 1, 256, CV_8UC1 )); |
| CV_CALL( cvCalcArrHist( (CvArr**)&src, hist )); |
| CV_CALL( img_sz = cvGetSize( src )); |
| scale = 255.f/(img_sz.width*img_sz.height); |
| h = (float*)cvPtr1D( hist->bins, 0 ); |
| |
| for( i = 0; i < hist_sz; i++ ) |
| { |
| sum += cvRound(h[i]); |
| lut->data.ptr[i] = (uchar)cvRound(sum*scale); |
| } |
| |
| lut->data.ptr[0] = 0; |
| CV_CALL( cvLUT( src, dst, lut )); |
| |
| __END__; |
| |
| cvReleaseHist(&hist); |
| cvReleaseMat(&lut); |
| } |
| |
| /* Implementation of RTTI and Generic Functions for CvHistogram */ |
| #define CV_TYPE_NAME_HIST "opencv-hist" |
| |
| static int icvIsHist( const void * ptr ){ |
| return CV_IS_HIST( ((CvHistogram*)ptr) ); |
| } |
| |
| static CvHistogram * icvCloneHist( const CvHistogram * src ){ |
| CvHistogram * dst=NULL; |
| cvCopyHist(src, &dst); |
| return dst; |
| } |
| |
| static void *icvReadHist( CvFileStorage * fs, CvFileNode * node ){ |
| CvHistogram * h = 0; |
| int is_uniform = 0; |
| int have_ranges = 0; |
| |
| CV_FUNCNAME("icvReadHist"); |
| __BEGIN__; |
| |
| CV_CALL( h = (CvHistogram *) cvAlloc( sizeof(CvHistogram) )); |
| |
| is_uniform = cvReadIntByName( fs, node, "is_uniform", 0 ); |
| have_ranges = cvReadIntByName( fs, node, "have_ranges", 0); |
| h->type = CV_HIST_MAGIC_VAL | |
| (is_uniform ? CV_HIST_UNIFORM_FLAG : 0) | |
| (have_ranges ? CV_HIST_RANGES_FLAG : 0); |
| |
| if(is_uniform){ |
| // read histogram bins |
| CvMatND * mat = (CvMatND *) cvReadByName( fs, node, "mat" ); |
| int sizes[CV_MAX_DIM]; |
| int i; |
| if(!CV_IS_MATND(mat)){ |
| CV_ERROR( CV_StsError, "Expected CvMatND"); |
| } |
| for(i=0; i<mat->dims; i++){ |
| sizes[i] = mat->dim[i].size; |
| } |
| |
| cvInitMatNDHeader( &(h->mat), mat->dims, sizes, mat->type, mat->data.ptr ); |
| h->bins = &(h->mat); |
| |
| // take ownership of refcount pointer as well |
| h->mat.refcount = mat->refcount; |
| |
| // increase refcount so freeing temp header doesn't free data |
| cvIncRefData( mat ); |
| |
| // free temporary header |
| cvReleaseMatND( &mat ); |
| } |
| else{ |
| h->bins = cvReadByName( fs, node, "bins" ); |
| if(!CV_IS_SPARSE_MAT(h->bins)){ |
| CV_ERROR( CV_StsError, "Unknown Histogram type"); |
| } |
| } |
| |
| // read thresholds |
| if(have_ranges){ |
| int i; |
| int dims; |
| int size[CV_MAX_DIM]; |
| int total = 0; |
| CvSeqReader reader; |
| CvFileNode * thresh_node; |
| |
| CV_CALL( dims = cvGetDims( h->bins, size )); |
| for( i = 0; i < dims; i++ ){ |
| total += size[i]+1; |
| } |
| |
| thresh_node = cvGetFileNodeByName( fs, node, "thresh" ); |
| if(!thresh_node){ |
| CV_ERROR( CV_StsError, "'thresh' node is missing"); |
| } |
| cvStartReadRawData( fs, thresh_node, &reader ); |
| |
| if(is_uniform){ |
| for(i=0; i<dims; i++){ |
| cvReadRawDataSlice( fs, &reader, 2, h->thresh[i], "f" ); |
| } |
| h->thresh2 = NULL; |
| } |
| else{ |
| float* dim_ranges; |
| CV_CALL( h->thresh2 = (float**)cvAlloc( |
| dims*sizeof(h->thresh2[0])+ |
| total*sizeof(h->thresh2[0][0]))); |
| dim_ranges = (float*)(h->thresh2 + dims); |
| for(i=0; i < dims; i++){ |
| h->thresh2[i] = dim_ranges; |
| cvReadRawDataSlice( fs, &reader, size[i]+1, dim_ranges, "f" ); |
| dim_ranges += size[i] + 1; |
| } |
| } |
| |
| } |
| |
| __END__; |
| |
| return h; |
| } |
| |
| static void icvWriteHist( CvFileStorage* fs, const char* name, const void* struct_ptr, |
| CvAttrList /*attributes*/ ){ |
| const CvHistogram * hist = (const CvHistogram *) struct_ptr; |
| int sizes[CV_MAX_DIM]; |
| int dims; |
| int i; |
| int is_uniform, have_ranges; |
| |
| CV_FUNCNAME("icvWriteHist"); |
| __BEGIN__; |
| |
| cvStartWriteStruct( fs, name, CV_NODE_MAP, CV_TYPE_NAME_HIST ); |
| |
| is_uniform = (CV_IS_UNIFORM_HIST(hist) ? 1 : 0); |
| have_ranges = (hist->type & CV_HIST_RANGES_FLAG ? 1 : 0); |
| |
| cvWriteInt( fs, "is_uniform", is_uniform ); |
| cvWriteInt( fs, "have_ranges", have_ranges ); |
| if(CV_IS_UNIFORM_HIST(hist)){ |
| cvWrite( fs, "mat", &(hist->mat) ); |
| } |
| else if(CV_IS_SPARSE_HIST(hist)){ |
| cvWrite( fs, "bins", hist->bins ); |
| } |
| else{ |
| CV_ERROR( CV_StsError, "Unknown Histogram Type" ); |
| } |
| |
| // write thresholds |
| if(have_ranges){ |
| dims = cvGetDims( hist->bins, sizes ); |
| cvStartWriteStruct( fs, "thresh", CV_NODE_SEQ + CV_NODE_FLOW ); |
| if(is_uniform){ |
| for(i=0; i<dims; i++){ |
| cvWriteRawData( fs, hist->thresh[i], 2, "f" ); |
| } |
| } |
| else{ |
| for(i=0; i<dims; i++){ |
| cvWriteRawData( fs, hist->thresh2[i], sizes[i]+1, "f" ); |
| } |
| } |
| cvEndWriteStruct( fs ); |
| } |
| |
| cvEndWriteStruct( fs ); |
| __END__; |
| } |
| |
| |
| CvType hist_type( CV_TYPE_NAME_HIST, icvIsHist, (CvReleaseFunc)cvReleaseHist, |
| icvReadHist, icvWriteHist, (CvCloneFunc)icvCloneHist ); |
| |
| /* End of file. */ |
| |