1 /*M///////////////////////////////////////////////////////////////////////////////////////
3 // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
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.
10 // Intel License Agreement
11 // For Open Source Computer Vision Library
13 // Copyright (C) 2000, Intel Corporation, all rights reserved.
14 // Third party copyrights are property of their respective owners.
16 // Redistribution and use in source and binary forms, with or without modification,
17 // are permitted provided that the following conditions are met:
19 // * Redistribution's of source code must retain the above copyright notice,
20 // this list of conditions and the following disclaimer.
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.
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.
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.
41 #include "precomp.hpp"
46 template<> void Ptr<CvHistogram>::delete_obj()
47 { cvReleaseHist(&obj); }
50 ////////////////// Helper functions //////////////////////
52 static const size_t OUT_OF_RANGE = (size_t)1 << (sizeof(size_t)*8 - 2);
55 calcHistLookupTables_8u( const Mat& hist, const SparseMat& shist,
56 int dims, const float** ranges, const double* uniranges,
57 bool uniform, bool issparse, vector<size_t>& _tab )
59 const int low = 0, high = 256;
61 _tab.resize((high-low)*dims);
62 size_t* tab = &_tab[0];
66 for( i = 0; i < dims; i++ )
68 double a = uniranges[i*2];
69 double b = uniranges[i*2+1];
70 int sz = !issparse ? hist.size[i] : shist.size(i);
71 size_t step = !issparse ? hist.step[i] : 1;
73 for( j = low; j < high; j++ )
75 int idx = cvFloor(j*a + b);
77 if( (unsigned)idx < (unsigned)sz )
78 written_idx = idx*step;
80 written_idx = OUT_OF_RANGE;
82 tab[i*(high - low) + j - low] = written_idx;
88 for( i = 0; i < dims; i++ )
90 int limit = std::min(cvCeil(ranges[i][0]), high);
91 int idx = -1, sz = !issparse ? hist.size[i] : shist.size(i);
92 size_t written_idx = OUT_OF_RANGE;
93 size_t step = !issparse ? hist.step[i] : 1;
97 for( ; j < limit; j++ )
98 tab[i*(high - low) + j - low] = written_idx;
100 if( (unsigned)(++idx) < (unsigned)sz )
102 limit = std::min(cvCeil(ranges[i][idx+1]), high);
103 written_idx = idx*step;
107 for( ; j < high; j++ )
108 tab[i*(high - low) + j - low] = OUT_OF_RANGE;
117 static void histPrepareImages( const Mat* images, int nimages, const int* channels,
118 const Mat& mask, int dims, const int* histSize,
119 const float** ranges, bool uniform,
120 vector<uchar*>& ptrs, vector<int>& deltas,
121 Size& imsize, vector<double>& uniranges )
124 CV_Assert( channels != 0 || nimages == dims );
126 imsize = images[0].size();
127 int depth = images[0].depth(), esz1 = (int)images[0].elemSize1();
128 bool isContinuous = true;
130 ptrs.resize(dims + 1);
131 deltas.resize((dims + 1)*2);
133 for( i = 0; i < dims; i++ )
139 CV_Assert( images[j].channels() == 1 );
145 for( j = 0; j < nimages; c -= images[j].channels(), j++ )
146 if( c < images[j].channels() )
148 CV_Assert( j < nimages );
151 CV_Assert( images[j].size() == imsize && images[j].depth() == depth );
152 if( !images[j].isContinuous() )
153 isContinuous = false;
154 ptrs[i] = images[j].data + c*esz1;
155 deltas[i*2] = images[j].channels();
156 deltas[i*2+1] = (int)(images[j].step/esz1 - imsize.width*deltas[i*2]);
161 CV_Assert( mask.size() == imsize && mask.channels() == 1 );
162 isContinuous = isContinuous && mask.isContinuous();
163 ptrs[dims] = mask.data;
165 deltas[dims*2 + 1] = (int)(mask.step/mask.elemSize1());
171 imsize.width *= imsize.height;
178 CV_Assert( depth == CV_8U );
180 uniranges.resize( dims*2 );
181 for( i = 0; i < dims; i++ )
183 uniranges[i*2] = histSize[i]/256.;
184 uniranges[i*2+1] = 0;
189 uniranges.resize( dims*2 );
190 for( i = 0; i < dims; i++ )
192 CV_Assert( ranges[i] && ranges[i][0] < ranges[i][1] );
193 double low = ranges[i][0], high = ranges[i][1];
194 double t = histSize[i]/(high - low);
196 uniranges[i*2+1] = -t*low;
201 for( i = 0; i < dims; i++ )
203 size_t n = histSize[i];
204 for(size_t k = 0; k < n; k++ )
205 CV_Assert( ranges[i][k] < ranges[i][k+1] );
211 ////////////////////////////////// C A L C U L A T E H I S T O G R A M ////////////////////////////////////
213 enum {one = 1, two, three}; // array elements number
216 class calcHist1D_Invoker
219 calcHist1D_Invoker( const vector<uchar*>& _ptrs, const vector<int>& _deltas,
220 Mat& hist, const double* _uniranges, int sz, int dims,
222 : mask_(_ptrs[dims]),
223 mstep_(_deltas[dims*2 + 1]),
224 imageWidth_(imageSize.width),
225 histogramSize_(hist.size()), histogramType_(hist.type()),
226 globalHistogram_((tbb::atomic<int>*)hist.data)
228 p_[0] = ((T**)&_ptrs[0])[0];
229 step_[0] = (&_deltas[0])[1];
230 d_[0] = (&_deltas[0])[0];
231 a_[0] = (&_uniranges[0])[0];
232 b_[0] = (&_uniranges[0])[1];
236 void operator()( const BlockedRange& range ) const
238 T* p0 = p_[0] + range.begin() * (step_[0] + imageWidth_*d_[0]);
239 uchar* mask = mask_ + range.begin()*mstep_;
241 for( int row = range.begin(); row < range.end(); row++, p0 += step_[0] )
245 for( int x = 0; x < imageWidth_; x++, p0 += d_[0] )
247 int idx = cvFloor(*p0*a_[0] + b_[0]);
248 if( (unsigned)idx < (unsigned)size_[0] )
250 globalHistogram_[idx].fetch_and_add(1);
256 for( int x = 0; x < imageWidth_; x++, p0 += d_[0] )
260 int idx = cvFloor(*p0*a_[0] + b_[0]);
261 if( (unsigned)idx < (unsigned)size_[0] )
263 globalHistogram_[idx].fetch_and_add(1);
284 tbb::atomic<int>* globalHistogram_;
288 class calcHist2D_Invoker
291 calcHist2D_Invoker( const vector<uchar*>& _ptrs, const vector<int>& _deltas,
292 Mat& hist, const double* _uniranges, const int* size,
293 int dims, Size& imageSize, size_t* hstep )
294 : mask_(_ptrs[dims]),
295 mstep_(_deltas[dims*2 + 1]),
296 imageWidth_(imageSize.width),
297 histogramSize_(hist.size()), histogramType_(hist.type()),
298 globalHistogram_(hist.data)
300 p_[0] = ((T**)&_ptrs[0])[0]; p_[1] = ((T**)&_ptrs[0])[1];
301 step_[0] = (&_deltas[0])[1]; step_[1] = (&_deltas[0])[3];
302 d_[0] = (&_deltas[0])[0]; d_[1] = (&_deltas[0])[2];
303 a_[0] = (&_uniranges[0])[0]; a_[1] = (&_uniranges[0])[2];
304 b_[0] = (&_uniranges[0])[1]; b_[1] = (&_uniranges[0])[3];
305 size_[0] = size[0]; size_[1] = size[1];
306 hstep_[0] = hstep[0];
309 void operator()(const BlockedRange& range) const
311 T* p0 = p_[0] + range.begin()*(step_[0] + imageWidth_*d_[0]);
312 T* p1 = p_[1] + range.begin()*(step_[1] + imageWidth_*d_[1]);
313 uchar* mask = mask_ + range.begin()*mstep_;
315 for( int row = range.begin(); row < range.end(); row++, p0 += step_[0], p1 += step_[1] )
319 for( int x = 0; x < imageWidth_; x++, p0 += d_[0], p1 += d_[1] )
321 int idx0 = cvFloor(*p0*a_[0] + b_[0]);
322 int idx1 = cvFloor(*p1*a_[1] + b_[1]);
323 if( (unsigned)idx0 < (unsigned)size_[0] && (unsigned)idx1 < (unsigned)size_[1] )
324 ( (tbb::atomic<int>*)(globalHistogram_ + hstep_[0]*idx0) )[idx1].fetch_and_add(1);
329 for( int x = 0; x < imageWidth_; x++, p0 += d_[0], p1 += d_[1] )
333 int idx0 = cvFloor(*p0*a_[0] + b_[0]);
334 int idx1 = cvFloor(*p1*a_[1] + b_[1]);
335 if( (unsigned)idx0 < (unsigned)size_[0] && (unsigned)idx1 < (unsigned)size_[1] )
336 ((tbb::atomic<int>*)(globalHistogram_ + hstep_[0]*idx0))[idx1].fetch_and_add(1);
353 const int imageWidth_;
357 uchar* globalHistogram_;
362 class calcHist3D_Invoker
365 calcHist3D_Invoker( const vector<uchar*>& _ptrs, const vector<int>& _deltas,
366 Size imsize, Mat& hist, const double* uniranges, int _dims,
367 size_t* hstep, int* size )
368 : mask_(_ptrs[_dims]),
369 mstep_(_deltas[_dims*2 + 1]),
370 imageWidth_(imsize.width),
371 globalHistogram_(hist.data)
373 p_[0] = ((T**)&_ptrs[0])[0]; p_[1] = ((T**)&_ptrs[0])[1]; p_[2] = ((T**)&_ptrs[0])[2];
374 step_[0] = (&_deltas[0])[1]; step_[1] = (&_deltas[0])[3]; step_[2] = (&_deltas[0])[5];
375 d_[0] = (&_deltas[0])[0]; d_[1] = (&_deltas[0])[2]; d_[2] = (&_deltas[0])[4];
376 a_[0] = uniranges[0]; a_[1] = uniranges[2]; a_[2] = uniranges[4];
377 b_[0] = uniranges[1]; b_[1] = uniranges[3]; b_[2] = uniranges[5];
378 size_[0] = size[0]; size_[1] = size[1]; size_[2] = size[2];
379 hstep_[0] = hstep[0]; hstep_[1] = hstep[1];
382 void operator()( const BlockedRange& range ) const
384 T* p0 = p_[0] + range.begin()*(imageWidth_*d_[0] + step_[0]);
385 T* p1 = p_[1] + range.begin()*(imageWidth_*d_[1] + step_[1]);
386 T* p2 = p_[2] + range.begin()*(imageWidth_*d_[2] + step_[2]);
387 uchar* mask = mask_ + range.begin()*mstep_;
389 for( int i = range.begin(); i < range.end(); i++, p0 += step_[0], p1 += step_[1], p2 += step_[2] )
393 for( int x = 0; x < imageWidth_; x++, p0 += d_[0], p1 += d_[1], p2 += d_[2] )
395 int idx0 = cvFloor(*p0*a_[0] + b_[0]);
396 int idx1 = cvFloor(*p1*a_[1] + b_[1]);
397 int idx2 = cvFloor(*p2*a_[2] + b_[2]);
398 if( (unsigned)idx0 < (unsigned)size_[0] &&
399 (unsigned)idx1 < (unsigned)size_[1] &&
400 (unsigned)idx2 < (unsigned)size_[2] )
402 ( (tbb::atomic<int>*)(globalHistogram_ + hstep_[0]*idx0 + hstep_[1]*idx1) )[idx2].fetch_and_add(1);
408 for( int x = 0; x < imageWidth_; x++, p0 += d_[0], p1 += d_[1], p2 += d_[2] )
412 int idx0 = cvFloor(*p0*a_[0] + b_[0]);
413 int idx1 = cvFloor(*p1*a_[1] + b_[1]);
414 int idx2 = cvFloor(*p2*a_[2] + b_[2]);
415 if( (unsigned)idx0 < (unsigned)size_[0] &&
416 (unsigned)idx1 < (unsigned)size_[1] &&
417 (unsigned)idx2 < (unsigned)size_[2] )
419 ( (tbb::atomic<int>*)(globalHistogram_ + hstep_[0]*idx0 + hstep_[1]*idx1) )[idx2].fetch_and_add(1);
428 static bool isFit( const Mat& histogram, const Size imageSize )
430 return ( imageSize.width * imageSize.height >= 320*240
431 && histogram.total() >= 8*8*8 );
445 uchar* globalHistogram_;
448 class CalcHist1D_8uInvoker
451 CalcHist1D_8uInvoker( const vector<uchar*>& ptrs, const vector<int>& deltas,
452 Size imsize, Mat& hist, int dims, const vector<size_t>& tab,
455 mstep_(deltas[dims*2 + 1]),
456 imageWidth_(imsize.width),
458 histSize_(hist.size()), histType_(hist.type()),
459 tab_((size_t*)&tab[0]),
460 histogramWriteLock_(lock),
461 globalHistogram_(hist.data)
463 p_[0] = (&ptrs[0])[0];
464 step_[0] = (&deltas[0])[1];
465 d_[0] = (&deltas[0])[0];
468 void operator()( const BlockedRange& range ) const
470 int localHistogram[256] = { 0, };
474 tbb::mutex::scoped_lock lock;
478 int n = (imageWidth_ - 4) / 4 + 1;
479 int tail = imageWidth_ - n*4;
482 p0 += (xN*d_[0] + tail*d_[0] + step_[0]) * range.begin();
486 p0 += (imageWidth_*d_[0] + step_[0]) * range.begin();
487 mask += mstep_*range.begin();
490 for( int i = range.begin(); i < range.end(); i++, p0 += step_[0] )
496 for( x = 0; x <= imageWidth_ - 4; x += 4 )
498 int t0 = p0[x], t1 = p0[x+1];
499 localHistogram[t0]++; localHistogram[t1]++;
500 t0 = p0[x+2]; t1 = p0[x+3];
501 localHistogram[t0]++; localHistogram[t1]++;
507 for( x = 0; x <= imageWidth_ - 4; x += 4 )
509 int t0 = p0[0], t1 = p0[d_[0]];
510 localHistogram[t0]++; localHistogram[t1]++;
512 t0 = p0[0]; t1 = p0[d_[0]];
513 localHistogram[t0]++; localHistogram[t1]++;
518 for( ; x < imageWidth_; x++, p0 += d_[0] )
520 localHistogram[*p0]++;
525 for( x = 0; x < imageWidth_; x++, p0 += d_[0] )
529 localHistogram[*p0]++;
536 lock.acquire(*histogramWriteLock_);
537 for(int i = 0; i < 256; i++ )
539 size_t hidx = tab_[i];
540 if( hidx < OUT_OF_RANGE )
542 *(int*)((globalHistogram_ + hidx)) += localHistogram[i];
548 static bool isFit( const Mat& histogram, const Size imageSize )
550 return ( histogram.total() >= 8
551 && imageSize.width * imageSize.height >= 160*120 );
565 tbb::mutex* histogramWriteLock_;
566 uchar* globalHistogram_;
569 class CalcHist2D_8uInvoker
572 CalcHist2D_8uInvoker( const vector<uchar*>& _ptrs, const vector<int>& _deltas,
573 Size imsize, Mat& hist, int dims, const vector<size_t>& _tab,
575 : mask_(_ptrs[dims]),
576 mstep_(_deltas[dims*2 + 1]),
577 imageWidth_(imsize.width),
578 histSize_(hist.size()), histType_(hist.type()),
579 tab_((size_t*)&_tab[0]),
580 histogramWriteLock_(lock),
581 globalHistogram_(hist.data)
583 p_[0] = (uchar*)(&_ptrs[0])[0]; p_[1] = (uchar*)(&_ptrs[0])[1];
584 step_[0] = (&_deltas[0])[1]; step_[1] = (&_deltas[0])[3];
585 d_[0] = (&_deltas[0])[0]; d_[1] = (&_deltas[0])[2];
588 void operator()( const BlockedRange& range ) const
590 uchar* p0 = p_[0] + range.begin()*(step_[0] + imageWidth_*d_[0]);
591 uchar* p1 = p_[1] + range.begin()*(step_[1] + imageWidth_*d_[1]);
592 uchar* mask = mask_ + range.begin()*mstep_;
594 Mat localHist = Mat::zeros(histSize_, histType_);
595 uchar* localHistData = localHist.data;
596 tbb::mutex::scoped_lock lock;
598 for(int i = range.begin(); i < range.end(); i++, p0 += step_[0], p1 += step_[1])
602 for( int x = 0; x < imageWidth_; x++, p0 += d_[0], p1 += d_[1] )
604 size_t idx = tab_[*p0] + tab_[*p1 + 256];
605 if( idx < OUT_OF_RANGE )
607 ++*(int*)(localHistData + idx);
613 for( int x = 0; x < imageWidth_; x++, p0 += d_[0], p1 += d_[1] )
616 if( mask[x] && (idx = tab_[*p0] + tab_[*p1 + 256]) < OUT_OF_RANGE )
618 ++*(int*)(localHistData + idx);
625 lock.acquire(*histogramWriteLock_);
626 for(int i = 0; i < histSize_.width*histSize_.height; i++)
628 ((int*)globalHistogram_)[i] += ((int*)localHistData)[i];
633 static bool isFit( const Mat& histogram, const Size imageSize )
635 return ( (histogram.total() > 4*4 && histogram.total() <= 116*116
636 && imageSize.width * imageSize.height >= 320*240)
637 || (histogram.total() > 116*116 && imageSize.width * imageSize.height >= 1280*720) );
650 tbb::mutex* histogramWriteLock_;
651 uchar* globalHistogram_;
654 class CalcHist3D_8uInvoker
657 CalcHist3D_8uInvoker( const vector<uchar*>& _ptrs, const vector<int>& _deltas,
658 Size imsize, Mat& hist, int dims, const vector<size_t>& tab )
659 : mask_(_ptrs[dims]),
660 mstep_(_deltas[dims*2 + 1]),
661 histogramSize_(hist.size.p), histogramType_(hist.type()),
662 imageWidth_(imsize.width),
663 tab_((size_t*)&tab[0]),
664 globalHistogram_(hist.data)
666 p_[0] = (uchar*)(&_ptrs[0])[0]; p_[1] = (uchar*)(&_ptrs[0])[1]; p_[2] = (uchar*)(&_ptrs[0])[2];
667 step_[0] = (&_deltas[0])[1]; step_[1] = (&_deltas[0])[3]; step_[2] = (&_deltas[0])[5];
668 d_[0] = (&_deltas[0])[0]; d_[1] = (&_deltas[0])[2]; d_[2] = (&_deltas[0])[4];
671 void operator()( const BlockedRange& range ) const
673 uchar* p0 = p_[0] + range.begin()*(step_[0] + imageWidth_*d_[0]);
674 uchar* p1 = p_[1] + range.begin()*(step_[1] + imageWidth_*d_[1]);
675 uchar* p2 = p_[2] + range.begin()*(step_[2] + imageWidth_*d_[2]);
676 uchar* mask = mask_ + range.begin()*mstep_;
678 for(int i = range.begin(); i < range.end(); i++, p0 += step_[0], p1 += step_[1], p2 += step_[2] )
682 for( int x = 0; x < imageWidth_; x++, p0 += d_[0], p1 += d_[1], p2 += d_[2] )
684 size_t idx = tab_[*p0] + tab_[*p1 + 256] + tab_[*p2 + 512];
685 if( idx < OUT_OF_RANGE )
687 ( *(tbb::atomic<int>*)(globalHistogram_ + idx) ).fetch_and_add(1);
693 for( int x = 0; x < imageWidth_; x++, p0 += d_[0], p1 += d_[1], p2 += d_[2] )
696 if( mask[x] && (idx = tab_[*p0] + tab_[*p1 + 256] + tab_[*p2 + 512]) < OUT_OF_RANGE )
698 (*(tbb::atomic<int>*)(globalHistogram_ + idx)).fetch_and_add(1);
706 static bool isFit( const Mat& histogram, const Size imageSize )
708 return ( histogram.total() >= 128*128*128
709 && imageSize.width * imageSize.width >= 320*240 );
722 uchar* globalHistogram_;
726 callCalcHist2D_8u( vector<uchar*>& _ptrs, const vector<int>& _deltas,
727 Size imsize, Mat& hist, int dims, vector<size_t>& _tab )
729 int grainSize = imsize.height / tbb::task_scheduler_init::default_num_threads();
730 tbb::mutex histogramWriteLock;
732 CalcHist2D_8uInvoker body(_ptrs, _deltas, imsize, hist, dims, _tab, &histogramWriteLock);
733 parallel_for(BlockedRange(0, imsize.height, grainSize), body);
737 callCalcHist3D_8u( vector<uchar*>& _ptrs, const vector<int>& _deltas,
738 Size imsize, Mat& hist, int dims, vector<size_t>& _tab )
740 CalcHist3D_8uInvoker body(_ptrs, _deltas, imsize, hist, dims, _tab);
741 parallel_for(BlockedRange(0, imsize.height), body);
745 template<typename T> static void
746 calcHist_( vector<uchar*>& _ptrs, const vector<int>& _deltas,
747 Size imsize, Mat& hist, int dims, const float** _ranges,
748 const double* _uniranges, bool uniform )
750 T** ptrs = (T**)&_ptrs[0];
751 const int* deltas = &_deltas[0];
752 uchar* H = hist.data;
754 const uchar* mask = _ptrs[dims];
755 int mstep = _deltas[dims*2 + 1];
756 int size[CV_MAX_DIM];
757 size_t hstep[CV_MAX_DIM];
759 for( i = 0; i < dims; i++ )
761 size[i] = hist.size[i];
762 hstep[i] = hist.step[i];
767 const double* uniranges = &_uniranges[0];
772 calcHist1D_Invoker<T> body(_ptrs, _deltas, hist, _uniranges, size[0], dims, imsize);
773 parallel_for(BlockedRange(0, imsize.height), body);
776 double a = uniranges[0], b = uniranges[1];
777 int sz = size[0], d0 = deltas[0], step0 = deltas[1];
778 const T* p0 = (const T*)ptrs[0];
780 for( ; imsize.height--; p0 += step0, mask += mstep )
783 for( x = 0; x < imsize.width; x++, p0 += d0 )
785 int idx = cvFloor(*p0*a + b);
786 if( (unsigned)idx < (unsigned)sz )
790 for( x = 0; x < imsize.width; x++, p0 += d0 )
793 int idx = cvFloor(*p0*a + b);
794 if( (unsigned)idx < (unsigned)sz )
802 calcHist2D_Invoker<T> body(_ptrs, _deltas, hist, _uniranges, size, dims, imsize, hstep);
803 parallel_for(BlockedRange(0, imsize.height), body);
806 double a0 = uniranges[0], b0 = uniranges[1], a1 = uniranges[2], b1 = uniranges[3];
807 int sz0 = size[0], sz1 = size[1];
808 int d0 = deltas[0], step0 = deltas[1],
809 d1 = deltas[2], step1 = deltas[3];
810 size_t hstep0 = hstep[0];
811 const T* p0 = (const T*)ptrs[0];
812 const T* p1 = (const T*)ptrs[1];
814 for( ; imsize.height--; p0 += step0, p1 += step1, mask += mstep )
817 for( x = 0; x < imsize.width; x++, p0 += d0, p1 += d1 )
819 int idx0 = cvFloor(*p0*a0 + b0);
820 int idx1 = cvFloor(*p1*a1 + b1);
821 if( (unsigned)idx0 < (unsigned)sz0 && (unsigned)idx1 < (unsigned)sz1 )
822 ((int*)(H + hstep0*idx0))[idx1]++;
825 for( x = 0; x < imsize.width; x++, p0 += d0, p1 += d1 )
828 int idx0 = cvFloor(*p0*a0 + b0);
829 int idx1 = cvFloor(*p1*a1 + b1);
830 if( (unsigned)idx0 < (unsigned)sz0 && (unsigned)idx1 < (unsigned)sz1 )
831 ((int*)(H + hstep0*idx0))[idx1]++;
838 if( calcHist3D_Invoker<T>::isFit(hist, imsize) )
840 calcHist3D_Invoker<T> body(_ptrs, _deltas, imsize, hist, uniranges, dims, hstep, size);
841 parallel_for(BlockedRange(0, imsize.height), body);
845 double a0 = uniranges[0], b0 = uniranges[1],
846 a1 = uniranges[2], b1 = uniranges[3],
847 a2 = uniranges[4], b2 = uniranges[5];
848 int sz0 = size[0], sz1 = size[1], sz2 = size[2];
849 int d0 = deltas[0], step0 = deltas[1],
850 d1 = deltas[2], step1 = deltas[3],
851 d2 = deltas[4], step2 = deltas[5];
852 size_t hstep0 = hstep[0], hstep1 = hstep[1];
853 const T* p0 = (const T*)ptrs[0];
854 const T* p1 = (const T*)ptrs[1];
855 const T* p2 = (const T*)ptrs[2];
857 for( ; imsize.height--; p0 += step0, p1 += step1, p2 += step2, mask += mstep )
860 for( x = 0; x < imsize.width; x++, p0 += d0, p1 += d1, p2 += d2 )
862 int idx0 = cvFloor(*p0*a0 + b0);
863 int idx1 = cvFloor(*p1*a1 + b1);
864 int idx2 = cvFloor(*p2*a2 + b2);
865 if( (unsigned)idx0 < (unsigned)sz0 &&
866 (unsigned)idx1 < (unsigned)sz1 &&
867 (unsigned)idx2 < (unsigned)sz2 )
868 ((int*)(H + hstep0*idx0 + hstep1*idx1))[idx2]++;
871 for( x = 0; x < imsize.width; x++, p0 += d0, p1 += d1, p2 += d2 )
874 int idx0 = cvFloor(*p0*a0 + b0);
875 int idx1 = cvFloor(*p1*a1 + b1);
876 int idx2 = cvFloor(*p2*a2 + b2);
877 if( (unsigned)idx0 < (unsigned)sz0 &&
878 (unsigned)idx1 < (unsigned)sz1 &&
879 (unsigned)idx2 < (unsigned)sz2 )
880 ((int*)(H + hstep0*idx0 + hstep1*idx1))[idx2]++;
886 for( ; imsize.height--; mask += mstep )
889 for( x = 0; x < imsize.width; x++ )
892 for( i = 0; i < dims; i++ )
894 int idx = cvFloor(*ptrs[i]*uniranges[i*2] + uniranges[i*2+1]);
895 if( (unsigned)idx >= (unsigned)size[i] )
897 ptrs[i] += deltas[i*2];
898 Hptr += idx*hstep[i];
904 for( ; i < dims; i++ )
905 ptrs[i] += deltas[i*2];
908 for( x = 0; x < imsize.width; x++ )
913 for( ; i < dims; i++ )
915 int idx = cvFloor(*ptrs[i]*uniranges[i*2] + uniranges[i*2+1]);
916 if( (unsigned)idx >= (unsigned)size[i] )
918 ptrs[i] += deltas[i*2];
919 Hptr += idx*hstep[i];
925 for( ; i < dims; i++ )
926 ptrs[i] += deltas[i*2];
928 for( i = 0; i < dims; i++ )
929 ptrs[i] += deltas[i*2 + 1];
935 // non-uniform histogram
936 const float* ranges[CV_MAX_DIM];
937 for( i = 0; i < dims; i++ )
938 ranges[i] = &_ranges[i][0];
940 for( ; imsize.height--; mask += mstep )
942 for( x = 0; x < imsize.width; x++ )
947 if( !mask || mask[x] )
948 for( ; i < dims; i++ )
950 float v = (float)*ptrs[i];
951 const float* R = ranges[i];
952 int idx = -1, sz = size[i];
954 while( v >= R[idx+1] && ++idx < sz )
957 if( (unsigned)idx >= (unsigned)sz )
960 ptrs[i] += deltas[i*2];
961 Hptr += idx*hstep[i];
967 for( ; i < dims; i++ )
968 ptrs[i] += deltas[i*2];
971 for( i = 0; i < dims; i++ )
972 ptrs[i] += deltas[i*2 + 1];
979 calcHist_8u( vector<uchar*>& _ptrs, const vector<int>& _deltas,
980 Size imsize, Mat& hist, int dims, const float** _ranges,
981 const double* _uniranges, bool uniform )
983 uchar** ptrs = &_ptrs[0];
984 const int* deltas = &_deltas[0];
985 uchar* H = hist.data;
987 const uchar* mask = _ptrs[dims];
988 int mstep = _deltas[dims*2 + 1];
991 calcHistLookupTables_8u( hist, SparseMat(), dims, _ranges, _uniranges, uniform, false, _tab );
992 const size_t* tab = &_tab[0];
997 if( CalcHist1D_8uInvoker::isFit(hist, imsize) )
999 int treadsNumber = tbb::task_scheduler_init::default_num_threads();
1000 int grainSize = imsize.height/treadsNumber;
1001 tbb::mutex histogramWriteLock;
1003 CalcHist1D_8uInvoker body(_ptrs, _deltas, imsize, hist, dims, _tab, &histogramWriteLock);
1004 parallel_for(BlockedRange(0, imsize.height, grainSize), body);
1008 int d0 = deltas[0], step0 = deltas[1];
1009 int matH[256] = { 0, };
1010 const uchar* p0 = (const uchar*)ptrs[0];
1012 for( ; imsize.height--; p0 += step0, mask += mstep )
1018 for( x = 0; x <= imsize.width - 4; x += 4 )
1020 int t0 = p0[x], t1 = p0[x+1];
1021 matH[t0]++; matH[t1]++;
1022 t0 = p0[x+2]; t1 = p0[x+3];
1023 matH[t0]++; matH[t1]++;
1028 for( x = 0; x <= imsize.width - 4; x += 4 )
1030 int t0 = p0[0], t1 = p0[d0];
1031 matH[t0]++; matH[t1]++;
1033 t0 = p0[0]; t1 = p0[d0];
1034 matH[t0]++; matH[t1]++;
1038 for( ; x < imsize.width; x++, p0 += d0 )
1042 for( x = 0; x < imsize.width; x++, p0 += d0 )
1047 for(int i = 0; i < 256; i++ )
1049 size_t hidx = tab[i];
1050 if( hidx < OUT_OF_RANGE )
1051 *(int*)(H + hidx) += matH[i];
1054 else if( dims == 2 )
1057 if( CalcHist2D_8uInvoker::isFit(hist, imsize) )
1059 callCalcHist2D_8u(_ptrs, _deltas, imsize, hist, dims, _tab);
1063 int d0 = deltas[0], step0 = deltas[1],
1064 d1 = deltas[2], step1 = deltas[3];
1065 const uchar* p0 = (const uchar*)ptrs[0];
1066 const uchar* p1 = (const uchar*)ptrs[1];
1068 for( ; imsize.height--; p0 += step0, p1 += step1, mask += mstep )
1071 for( x = 0; x < imsize.width; x++, p0 += d0, p1 += d1 )
1073 size_t idx = tab[*p0] + tab[*p1 + 256];
1074 if( idx < OUT_OF_RANGE )
1078 for( x = 0; x < imsize.width; x++, p0 += d0, p1 += d1 )
1081 if( mask[x] && (idx = tab[*p0] + tab[*p1 + 256]) < OUT_OF_RANGE )
1086 else if( dims == 3 )
1089 if( CalcHist3D_8uInvoker::isFit(hist, imsize) )
1091 callCalcHist3D_8u(_ptrs, _deltas, imsize, hist, dims, _tab);
1095 int d0 = deltas[0], step0 = deltas[1],
1096 d1 = deltas[2], step1 = deltas[3],
1097 d2 = deltas[4], step2 = deltas[5];
1099 const uchar* p0 = (const uchar*)ptrs[0];
1100 const uchar* p1 = (const uchar*)ptrs[1];
1101 const uchar* p2 = (const uchar*)ptrs[2];
1103 for( ; imsize.height--; p0 += step0, p1 += step1, p2 += step2, mask += mstep )
1106 for( x = 0; x < imsize.width; x++, p0 += d0, p1 += d1, p2 += d2 )
1108 size_t idx = tab[*p0] + tab[*p1 + 256] + tab[*p2 + 512];
1109 if( idx < OUT_OF_RANGE )
1113 for( x = 0; x < imsize.width; x++, p0 += d0, p1 += d1, p2 += d2 )
1116 if( mask[x] && (idx = tab[*p0] + tab[*p1 + 256] + tab[*p2 + 512]) < OUT_OF_RANGE )
1123 for( ; imsize.height--; mask += mstep )
1126 for( x = 0; x < imsize.width; x++ )
1130 for( ; i < dims; i++ )
1132 size_t idx = tab[*ptrs[i] + i*256];
1133 if( idx >= OUT_OF_RANGE )
1136 ptrs[i] += deltas[i*2];
1142 for( ; i < dims; i++ )
1143 ptrs[i] += deltas[i*2];
1146 for( x = 0; x < imsize.width; x++ )
1151 for( ; i < dims; i++ )
1153 size_t idx = tab[*ptrs[i] + i*256];
1154 if( idx >= OUT_OF_RANGE )
1157 ptrs[i] += deltas[i*2];
1163 for( ; i < dims; i++ )
1164 ptrs[i] += deltas[i*2];
1166 for(int i = 0; i < dims; i++ )
1167 ptrs[i] += deltas[i*2 + 1];
1174 void cv::calcHist( const Mat* images, int nimages, const int* channels,
1175 InputArray _mask, OutputArray _hist, int dims, const int* histSize,
1176 const float** ranges, bool uniform, bool accumulate )
1178 Mat mask = _mask.getMat();
1180 CV_Assert(dims > 0 && histSize);
1182 uchar* histdata = _hist.getMat().data;
1183 _hist.create(dims, histSize, CV_32F);
1184 Mat hist = _hist.getMat(), ihist = hist;
1185 ihist.flags = (ihist.flags & ~CV_MAT_TYPE_MASK)|CV_32S;
1187 if( !accumulate || histdata != hist.data )
1190 hist.convertTo(ihist, CV_32S);
1192 vector<uchar*> ptrs;
1194 vector<double> uniranges;
1197 CV_Assert( !mask.data || mask.type() == CV_8UC1 );
1198 histPrepareImages( images, nimages, channels, mask, dims, hist.size, ranges,
1199 uniform, ptrs, deltas, imsize, uniranges );
1200 const double* _uniranges = uniform ? &uniranges[0] : 0;
1202 int depth = images[0].depth();
1204 if( depth == CV_8U )
1205 calcHist_8u(ptrs, deltas, imsize, ihist, dims, ranges, _uniranges, uniform );
1206 else if( depth == CV_16U )
1207 calcHist_<ushort>(ptrs, deltas, imsize, ihist, dims, ranges, _uniranges, uniform );
1208 else if( depth == CV_32F )
1209 calcHist_<float>(ptrs, deltas, imsize, ihist, dims, ranges, _uniranges, uniform );
1211 CV_Error(CV_StsUnsupportedFormat, "");
1213 ihist.convertTo(hist, CV_32F);
1220 template<typename T> static void
1221 calcSparseHist_( vector<uchar*>& _ptrs, const vector<int>& _deltas,
1222 Size imsize, SparseMat& hist, int dims, const float** _ranges,
1223 const double* _uniranges, bool uniform )
1225 T** ptrs = (T**)&_ptrs[0];
1226 const int* deltas = &_deltas[0];
1228 const uchar* mask = _ptrs[dims];
1229 int mstep = _deltas[dims*2 + 1];
1230 const int* size = hist.hdr->size;
1231 int idx[CV_MAX_DIM];
1235 const double* uniranges = &_uniranges[0];
1237 for( ; imsize.height--; mask += mstep )
1239 for( x = 0; x < imsize.width; x++ )
1242 if( !mask || mask[x] )
1243 for( ; i < dims; i++ )
1245 idx[i] = cvFloor(*ptrs[i]*uniranges[i*2] + uniranges[i*2+1]);
1246 if( (unsigned)idx[i] >= (unsigned)size[i] )
1248 ptrs[i] += deltas[i*2];
1252 ++*(int*)hist.ptr(idx, true);
1254 for( ; i < dims; i++ )
1255 ptrs[i] += deltas[i*2];
1257 for( i = 0; i < dims; i++ )
1258 ptrs[i] += deltas[i*2 + 1];
1263 // non-uniform histogram
1264 const float* ranges[CV_MAX_DIM];
1265 for( i = 0; i < dims; i++ )
1266 ranges[i] = &_ranges[i][0];
1268 for( ; imsize.height--; mask += mstep )
1270 for( x = 0; x < imsize.width; x++ )
1274 if( !mask || mask[x] )
1275 for( ; i < dims; i++ )
1277 float v = (float)*ptrs[i];
1278 const float* R = ranges[i];
1279 int j = -1, sz = size[i];
1281 while( v >= R[j+1] && ++j < sz )
1284 if( (unsigned)j >= (unsigned)sz )
1286 ptrs[i] += deltas[i*2];
1291 ++*(int*)hist.ptr(idx, true);
1293 for( ; i < dims; i++ )
1294 ptrs[i] += deltas[i*2];
1297 for( i = 0; i < dims; i++ )
1298 ptrs[i] += deltas[i*2 + 1];
1305 calcSparseHist_8u( vector<uchar*>& _ptrs, const vector<int>& _deltas,
1306 Size imsize, SparseMat& hist, int dims, const float** _ranges,
1307 const double* _uniranges, bool uniform )
1309 uchar** ptrs = (uchar**)&_ptrs[0];
1310 const int* deltas = &_deltas[0];
1312 const uchar* mask = _ptrs[dims];
1313 int mstep = _deltas[dims*2 + 1];
1314 int idx[CV_MAX_DIM];
1315 vector<size_t> _tab;
1317 calcHistLookupTables_8u( Mat(), hist, dims, _ranges, _uniranges, uniform, true, _tab );
1318 const size_t* tab = &_tab[0];
1320 for( ; imsize.height--; mask += mstep )
1322 for( x = 0; x < imsize.width; x++ )
1325 if( !mask || mask[x] )
1326 for( ; i < dims; i++ )
1328 size_t hidx = tab[*ptrs[i] + i*256];
1329 if( hidx >= OUT_OF_RANGE )
1331 ptrs[i] += deltas[i*2];
1336 ++*(int*)hist.ptr(idx,true);
1338 for( ; i < dims; i++ )
1339 ptrs[i] += deltas[i*2];
1341 for(int i = 0; i < dims; i++ )
1342 ptrs[i] += deltas[i*2 + 1];
1347 static void calcHist( const Mat* images, int nimages, const int* channels,
1348 const Mat& mask, SparseMat& hist, int dims, const int* histSize,
1349 const float** ranges, bool uniform, bool accumulate, bool keepInt )
1354 hist.create(dims, histSize, CV_32F);
1357 SparseMatIterator it = hist.begin();
1358 for( i = 0, N = hist.nzcount(); i < N; i++, ++it )
1360 Cv32suf* val = (Cv32suf*)it.ptr;
1361 val->i = cvRound(val->f);
1365 vector<uchar*> ptrs;
1367 vector<double> uniranges;
1370 CV_Assert( !mask.data || mask.type() == CV_8UC1 );
1371 histPrepareImages( images, nimages, channels, mask, dims, hist.hdr->size, ranges,
1372 uniform, ptrs, deltas, imsize, uniranges );
1373 const double* _uniranges = uniform ? &uniranges[0] : 0;
1375 int depth = images[0].depth();
1376 if( depth == CV_8U )
1377 calcSparseHist_8u(ptrs, deltas, imsize, hist, dims, ranges, _uniranges, uniform );
1378 else if( depth == CV_16U )
1379 calcSparseHist_<ushort>(ptrs, deltas, imsize, hist, dims, ranges, _uniranges, uniform );
1380 else if( depth == CV_32F )
1381 calcSparseHist_<float>(ptrs, deltas, imsize, hist, dims, ranges, _uniranges, uniform );
1383 CV_Error(CV_StsUnsupportedFormat, "");
1387 SparseMatIterator it = hist.begin();
1388 for( i = 0, N = hist.nzcount(); i < N; i++, ++it )
1390 Cv32suf* val = (Cv32suf*)it.ptr;
1391 val->f = (float)val->i;
1398 void cv::calcHist( const Mat* images, int nimages, const int* channels,
1399 InputArray _mask, SparseMat& hist, int dims, const int* histSize,
1400 const float** ranges, bool uniform, bool accumulate )
1402 Mat mask = _mask.getMat();
1403 calcHist( images, nimages, channels, mask, hist, dims, histSize,
1404 ranges, uniform, accumulate, false );
1408 void cv::calcHist( InputArrayOfArrays images, const vector<int>& channels,
1409 InputArray mask, OutputArray hist,
1410 const vector<int>& histSize,
1411 const vector<float>& ranges,
1414 int i, dims = (int)histSize.size(), rsz = (int)ranges.size(), csz = (int)channels.size();
1415 int nimages = (int)images.total();
1417 CV_Assert(nimages > 0 && dims > 0);
1418 CV_Assert(rsz == dims*2 || (rsz == 0 && images.depth(0) == CV_8U));
1419 CV_Assert(csz == 0 || csz == dims);
1420 float* _ranges[CV_MAX_DIM];
1423 for( i = 0; i < rsz/2; i++ )
1424 _ranges[i] = (float*)&ranges[i*2];
1427 AutoBuffer<Mat> buf(nimages);
1428 for( i = 0; i < nimages; i++ )
1429 buf[i] = images.getMat(i);
1431 calcHist(&buf[0], nimages, csz ? &channels[0] : 0,
1432 mask, hist, dims, &histSize[0], rsz ? (const float**)_ranges : 0,
1437 /////////////////////////////////////// B A C K P R O J E C T ////////////////////////////////////
1442 template<typename T, typename BT> static void
1443 calcBackProj_( vector<uchar*>& _ptrs, const vector<int>& _deltas,
1444 Size imsize, const Mat& hist, int dims, const float** _ranges,
1445 const double* _uniranges, float scale, bool uniform )
1447 T** ptrs = (T**)&_ptrs[0];
1448 const int* deltas = &_deltas[0];
1449 uchar* H = hist.data;
1451 BT* bproj = (BT*)_ptrs[dims];
1452 int bpstep = _deltas[dims*2 + 1];
1453 int size[CV_MAX_DIM];
1454 size_t hstep[CV_MAX_DIM];
1456 for( i = 0; i < dims; i++ )
1458 size[i] = hist.size[i];
1459 hstep[i] = hist.step[i];
1464 const double* uniranges = &_uniranges[0];
1468 double a = uniranges[0], b = uniranges[1];
1469 int sz = size[0], d0 = deltas[0], step0 = deltas[1];
1470 const T* p0 = (const T*)ptrs[0];
1472 for( ; imsize.height--; p0 += step0, bproj += bpstep )
1474 for( x = 0; x < imsize.width; x++, p0 += d0 )
1476 int idx = cvFloor(*p0*a + b);
1477 bproj[x] = (unsigned)idx < (unsigned)sz ? saturate_cast<BT>(((float*)H)[idx]*scale) : 0;
1481 else if( dims == 2 )
1483 double a0 = uniranges[0], b0 = uniranges[1],
1484 a1 = uniranges[2], b1 = uniranges[3];
1485 int sz0 = size[0], sz1 = size[1];
1486 int d0 = deltas[0], step0 = deltas[1],
1487 d1 = deltas[2], step1 = deltas[3];
1488 size_t hstep0 = hstep[0];
1489 const T* p0 = (const T*)ptrs[0];
1490 const T* p1 = (const T*)ptrs[1];
1492 for( ; imsize.height--; p0 += step0, p1 += step1, bproj += bpstep )
1494 for( x = 0; x < imsize.width; x++, p0 += d0, p1 += d1 )
1496 int idx0 = cvFloor(*p0*a0 + b0);
1497 int idx1 = cvFloor(*p1*a1 + b1);
1498 bproj[x] = (unsigned)idx0 < (unsigned)sz0 &&
1499 (unsigned)idx1 < (unsigned)sz1 ?
1500 saturate_cast<BT>(((float*)(H + hstep0*idx0))[idx1]*scale) : 0;
1504 else if( dims == 3 )
1506 double a0 = uniranges[0], b0 = uniranges[1],
1507 a1 = uniranges[2], b1 = uniranges[3],
1508 a2 = uniranges[4], b2 = uniranges[5];
1509 int sz0 = size[0], sz1 = size[1], sz2 = size[2];
1510 int d0 = deltas[0], step0 = deltas[1],
1511 d1 = deltas[2], step1 = deltas[3],
1512 d2 = deltas[4], step2 = deltas[5];
1513 size_t hstep0 = hstep[0], hstep1 = hstep[1];
1514 const T* p0 = (const T*)ptrs[0];
1515 const T* p1 = (const T*)ptrs[1];
1516 const T* p2 = (const T*)ptrs[2];
1518 for( ; imsize.height--; p0 += step0, p1 += step1, p2 += step2, bproj += bpstep )
1520 for( x = 0; x < imsize.width; x++, p0 += d0, p1 += d1, p2 += d2 )
1522 int idx0 = cvFloor(*p0*a0 + b0);
1523 int idx1 = cvFloor(*p1*a1 + b1);
1524 int idx2 = cvFloor(*p2*a2 + b2);
1525 bproj[x] = (unsigned)idx0 < (unsigned)sz0 &&
1526 (unsigned)idx1 < (unsigned)sz1 &&
1527 (unsigned)idx2 < (unsigned)sz2 ?
1528 saturate_cast<BT>(((float*)(H + hstep0*idx0 + hstep1*idx1))[idx2]*scale) : 0;
1534 for( ; imsize.height--; bproj += bpstep )
1536 for( x = 0; x < imsize.width; x++ )
1539 for( i = 0; i < dims; i++ )
1541 int idx = cvFloor(*ptrs[i]*uniranges[i*2] + uniranges[i*2+1]);
1542 if( (unsigned)idx >= (unsigned)size[i] || (_ranges && *ptrs[i] >= _ranges[i][1]))
1544 ptrs[i] += deltas[i*2];
1545 Hptr += idx*hstep[i];
1549 bproj[x] = saturate_cast<BT>(*(float*)Hptr*scale);
1553 for( ; i < dims; i++ )
1554 ptrs[i] += deltas[i*2];
1557 for( i = 0; i < dims; i++ )
1558 ptrs[i] += deltas[i*2 + 1];
1564 // non-uniform histogram
1565 const float* ranges[CV_MAX_DIM];
1566 for( i = 0; i < dims; i++ )
1567 ranges[i] = &_ranges[i][0];
1569 for( ; imsize.height--; bproj += bpstep )
1571 for( x = 0; x < imsize.width; x++ )
1574 for( i = 0; i < dims; i++ )
1576 float v = (float)*ptrs[i];
1577 const float* R = ranges[i];
1578 int idx = -1, sz = size[i];
1580 while( v >= R[idx+1] && ++idx < sz )
1583 if( (unsigned)idx >= (unsigned)sz )
1586 ptrs[i] += deltas[i*2];
1587 Hptr += idx*hstep[i];
1591 bproj[x] = saturate_cast<BT>(*(float*)Hptr*scale);
1595 for( ; i < dims; i++ )
1596 ptrs[i] += deltas[i*2];
1600 for( i = 0; i < dims; i++ )
1601 ptrs[i] += deltas[i*2 + 1];
1608 calcBackProj_8u( vector<uchar*>& _ptrs, const vector<int>& _deltas,
1609 Size imsize, const Mat& hist, int dims, const float** _ranges,
1610 const double* _uniranges, float scale, bool uniform )
1612 uchar** ptrs = &_ptrs[0];
1613 const int* deltas = &_deltas[0];
1614 uchar* H = hist.data;
1616 uchar* bproj = _ptrs[dims];
1617 int bpstep = _deltas[dims*2 + 1];
1618 vector<size_t> _tab;
1620 calcHistLookupTables_8u( hist, SparseMat(), dims, _ranges, _uniranges, uniform, false, _tab );
1621 const size_t* tab = &_tab[0];
1625 int d0 = deltas[0], step0 = deltas[1];
1626 uchar matH[256] = {0};
1627 const uchar* p0 = (const uchar*)ptrs[0];
1629 for( i = 0; i < 256; i++ )
1631 size_t hidx = tab[i];
1632 if( hidx < OUT_OF_RANGE )
1633 matH[i] = saturate_cast<uchar>(*(float*)(H + hidx)*scale);
1636 for( ; imsize.height--; p0 += step0, bproj += bpstep )
1640 for( x = 0; x <= imsize.width - 4; x += 4 )
1642 uchar t0 = matH[p0[x]], t1 = matH[p0[x+1]];
1643 bproj[x] = t0; bproj[x+1] = t1;
1644 t0 = matH[p0[x+2]]; t1 = matH[p0[x+3]];
1645 bproj[x+2] = t0; bproj[x+3] = t1;
1650 for( x = 0; x <= imsize.width - 4; x += 4 )
1652 uchar t0 = matH[p0[0]], t1 = matH[p0[d0]];
1653 bproj[x] = t0; bproj[x+1] = t1;
1655 t0 = matH[p0[0]]; t1 = matH[p0[d0]];
1656 bproj[x+2] = t0; bproj[x+3] = t1;
1660 for( ; x < imsize.width; x++, p0 += d0 )
1661 bproj[x] = matH[*p0];
1664 else if( dims == 2 )
1666 int d0 = deltas[0], step0 = deltas[1],
1667 d1 = deltas[2], step1 = deltas[3];
1668 const uchar* p0 = (const uchar*)ptrs[0];
1669 const uchar* p1 = (const uchar*)ptrs[1];
1671 for( ; imsize.height--; p0 += step0, p1 += step1, bproj += bpstep )
1673 for( x = 0; x < imsize.width; x++, p0 += d0, p1 += d1 )
1675 size_t idx = tab[*p0] + tab[*p1 + 256];
1676 bproj[x] = idx < OUT_OF_RANGE ? saturate_cast<uchar>(*(float*)(H + idx)*scale) : 0;
1680 else if( dims == 3 )
1682 int d0 = deltas[0], step0 = deltas[1],
1683 d1 = deltas[2], step1 = deltas[3],
1684 d2 = deltas[4], step2 = deltas[5];
1685 const uchar* p0 = (const uchar*)ptrs[0];
1686 const uchar* p1 = (const uchar*)ptrs[1];
1687 const uchar* p2 = (const uchar*)ptrs[2];
1689 for( ; imsize.height--; p0 += step0, p1 += step1, p2 += step2, bproj += bpstep )
1691 for( x = 0; x < imsize.width; x++, p0 += d0, p1 += d1, p2 += d2 )
1693 size_t idx = tab[*p0] + tab[*p1 + 256] + tab[*p2 + 512];
1694 bproj[x] = idx < OUT_OF_RANGE ? saturate_cast<uchar>(*(float*)(H + idx)*scale) : 0;
1700 for( ; imsize.height--; bproj += bpstep )
1702 for( x = 0; x < imsize.width; x++ )
1705 for( i = 0; i < dims; i++ )
1707 size_t idx = tab[*ptrs[i] + i*256];
1708 if( idx >= OUT_OF_RANGE )
1710 ptrs[i] += deltas[i*2];
1715 bproj[x] = saturate_cast<uchar>(*(float*)Hptr*scale);
1719 for( ; i < dims; i++ )
1720 ptrs[i] += deltas[i*2];
1723 for( i = 0; i < dims; i++ )
1724 ptrs[i] += deltas[i*2 + 1];
1731 void cv::calcBackProject( const Mat* images, int nimages, const int* channels,
1732 InputArray _hist, OutputArray _backProject,
1733 const float** ranges, double scale, bool uniform )
1735 Mat hist = _hist.getMat();
1736 vector<uchar*> ptrs;
1738 vector<double> uniranges;
1740 int dims = hist.dims == 2 && hist.size[1] == 1 ? 1 : hist.dims;
1742 CV_Assert( dims > 0 && hist.data );
1743 _backProject.create( images[0].size(), images[0].depth() );
1744 Mat backProject = _backProject.getMat();
1745 histPrepareImages( images, nimages, channels, backProject, dims, hist.size, ranges,
1746 uniform, ptrs, deltas, imsize, uniranges );
1747 const double* _uniranges = uniform ? &uniranges[0] : 0;
1749 int depth = images[0].depth();
1750 if( depth == CV_8U )
1751 calcBackProj_8u(ptrs, deltas, imsize, hist, dims, ranges, _uniranges, (float)scale, uniform);
1752 else if( depth == CV_16U )
1753 calcBackProj_<ushort, ushort>(ptrs, deltas, imsize, hist, dims, ranges, _uniranges, (float)scale, uniform );
1754 else if( depth == CV_32F )
1755 calcBackProj_<float, float>(ptrs, deltas, imsize, hist, dims, ranges, _uniranges, (float)scale, uniform );
1757 CV_Error(CV_StsUnsupportedFormat, "");
1764 template<typename T, typename BT> static void
1765 calcSparseBackProj_( vector<uchar*>& _ptrs, const vector<int>& _deltas,
1766 Size imsize, const SparseMat& hist, int dims, const float** _ranges,
1767 const double* _uniranges, float scale, bool uniform )
1769 T** ptrs = (T**)&_ptrs[0];
1770 const int* deltas = &_deltas[0];
1772 BT* bproj = (BT*)_ptrs[dims];
1773 int bpstep = _deltas[dims*2 + 1];
1774 const int* size = hist.hdr->size;
1775 int idx[CV_MAX_DIM];
1776 const SparseMat_<float>& hist_ = (const SparseMat_<float>&)hist;
1780 const double* uniranges = &_uniranges[0];
1781 for( ; imsize.height--; bproj += bpstep )
1783 for( x = 0; x < imsize.width; x++ )
1785 for( i = 0; i < dims; i++ )
1787 idx[i] = cvFloor(*ptrs[i]*uniranges[i*2] + uniranges[i*2+1]);
1788 if( (unsigned)idx[i] >= (unsigned)size[i] )
1790 ptrs[i] += deltas[i*2];
1794 bproj[x] = saturate_cast<BT>(hist_(idx)*scale);
1798 for( ; i < dims; i++ )
1799 ptrs[i] += deltas[i*2];
1802 for( i = 0; i < dims; i++ )
1803 ptrs[i] += deltas[i*2 + 1];
1808 // non-uniform histogram
1809 const float* ranges[CV_MAX_DIM];
1810 for( i = 0; i < dims; i++ )
1811 ranges[i] = &_ranges[i][0];
1813 for( ; imsize.height--; bproj += bpstep )
1815 for( x = 0; x < imsize.width; x++ )
1817 for( i = 0; i < dims; i++ )
1819 float v = (float)*ptrs[i];
1820 const float* R = ranges[i];
1821 int j = -1, sz = size[i];
1823 while( v >= R[j+1] && ++j < sz )
1826 if( (unsigned)j >= (unsigned)sz )
1829 ptrs[i] += deltas[i*2];
1833 bproj[x] = saturate_cast<BT>(hist_(idx)*scale);
1837 for( ; i < dims; i++ )
1838 ptrs[i] += deltas[i*2];
1842 for( i = 0; i < dims; i++ )
1843 ptrs[i] += deltas[i*2 + 1];
1850 calcSparseBackProj_8u( vector<uchar*>& _ptrs, const vector<int>& _deltas,
1851 Size imsize, const SparseMat& hist, int dims, const float** _ranges,
1852 const double* _uniranges, float scale, bool uniform )
1854 uchar** ptrs = &_ptrs[0];
1855 const int* deltas = &_deltas[0];
1857 uchar* bproj = _ptrs[dims];
1858 int bpstep = _deltas[dims*2 + 1];
1859 vector<size_t> _tab;
1860 int idx[CV_MAX_DIM];
1862 calcHistLookupTables_8u( Mat(), hist, dims, _ranges, _uniranges, uniform, true, _tab );
1863 const size_t* tab = &_tab[0];
1865 for( ; imsize.height--; bproj += bpstep )
1867 for( x = 0; x < imsize.width; x++ )
1869 for( i = 0; i < dims; i++ )
1871 size_t hidx = tab[*ptrs[i] + i*256];
1872 if( hidx >= OUT_OF_RANGE )
1875 ptrs[i] += deltas[i*2];
1879 bproj[x] = saturate_cast<uchar>(hist.value<float>(idx)*scale);
1883 for( ; i < dims; i++ )
1884 ptrs[i] += deltas[i*2];
1887 for( i = 0; i < dims; i++ )
1888 ptrs[i] += deltas[i*2 + 1];
1894 void cv::calcBackProject( const Mat* images, int nimages, const int* channels,
1895 const SparseMat& hist, OutputArray _backProject,
1896 const float** ranges, double scale, bool uniform )
1898 vector<uchar*> ptrs;
1900 vector<double> uniranges;
1902 int dims = hist.dims();
1904 CV_Assert( dims > 0 );
1905 _backProject.create( images[0].size(), images[0].depth() );
1906 Mat backProject = _backProject.getMat();
1907 histPrepareImages( images, nimages, channels, backProject,
1908 dims, hist.hdr->size, ranges,
1909 uniform, ptrs, deltas, imsize, uniranges );
1910 const double* _uniranges = uniform ? &uniranges[0] : 0;
1912 int depth = images[0].depth();
1913 if( depth == CV_8U )
1914 calcSparseBackProj_8u(ptrs, deltas, imsize, hist, dims, ranges,
1915 _uniranges, (float)scale, uniform);
1916 else if( depth == CV_16U )
1917 calcSparseBackProj_<ushort, ushort>(ptrs, deltas, imsize, hist, dims, ranges,
1918 _uniranges, (float)scale, uniform );
1919 else if( depth == CV_32F )
1920 calcSparseBackProj_<float, float>(ptrs, deltas, imsize, hist, dims, ranges,
1921 _uniranges, (float)scale, uniform );
1923 CV_Error(CV_StsUnsupportedFormat, "");
1927 void cv::calcBackProject( InputArrayOfArrays images, const vector<int>& channels,
1928 InputArray hist, OutputArray dst,
1929 const vector<float>& ranges,
1932 Mat H0 = hist.getMat(), H;
1933 int hcn = H0.channels();
1936 CV_Assert( H0.isContinuous() );
1937 int hsz[CV_CN_MAX+1];
1938 memcpy(hsz, &H0.size[0], H0.dims*sizeof(hsz[0]));
1940 H = Mat(H0.dims+1, hsz, H0.depth(), H0.data);
1944 bool _1d = H.rows == 1 || H.cols == 1;
1945 int i, dims = H.dims, rsz = (int)ranges.size(), csz = (int)channels.size();
1946 int nimages = (int)images.total();
1947 CV_Assert(nimages > 0);
1948 CV_Assert(rsz == dims*2 || (rsz == 2 && _1d) || (rsz == 0 && images.depth(0) == CV_8U));
1949 CV_Assert(csz == 0 || csz == dims || (csz == 1 && _1d));
1950 float* _ranges[CV_MAX_DIM];
1953 for( i = 0; i < rsz/2; i++ )
1954 _ranges[i] = (float*)&ranges[i*2];
1957 AutoBuffer<Mat> buf(nimages);
1958 for( i = 0; i < nimages; i++ )
1959 buf[i] = images.getMat(i);
1961 calcBackProject(&buf[0], nimages, csz ? &channels[0] : 0,
1962 hist, dst, rsz ? (const float**)_ranges : 0, scale, true);
1966 ////////////////// C O M P A R E H I S T O G R A M S ////////////////////////
1968 double cv::compareHist( InputArray _H1, InputArray _H2, int method )
1970 Mat H1 = _H1.getMat(), H2 = _H2.getMat();
1971 const Mat* arrays[] = {&H1, &H2, 0};
1973 NAryMatIterator it(arrays, planes);
1975 int j, len = (int)it.size;
1977 CV_Assert( H1.type() == H2.type() && H1.type() == CV_32F );
1979 double s1 = 0, s2 = 0, s11 = 0, s12 = 0, s22 = 0;
1981 CV_Assert( it.planes[0].isContinuous() && it.planes[1].isContinuous() );
1983 for( size_t i = 0; i < it.nplanes; i++, ++it )
1985 const float* h1 = (const float*)it.planes[0].data;
1986 const float* h2 = (const float*)it.planes[1].data;
1987 len = it.planes[0].rows*it.planes[0].cols;
1989 if( method == CV_COMP_CHISQR )
1991 for( j = 0; j < len; j++ )
1993 double a = h1[j] - h2[j];
1995 if( fabs(b) > DBL_EPSILON )
1999 else if( method == CV_COMP_CORREL )
2001 for( j = 0; j < len; j++ )
2013 else if( method == CV_COMP_INTERSECT )
2015 for( j = 0; j < len; j++ )
2016 result += std::min(h1[j], h2[j]);
2018 else if( method == CV_COMP_BHATTACHARYYA )
2020 for( j = 0; j < len; j++ )
2024 result += std::sqrt(a*b);
2030 CV_Error( CV_StsBadArg, "Unknown comparison method" );
2033 if( method == CV_COMP_CORREL )
2035 size_t total = H1.total();
2036 double scale = 1./total;
2037 double num = s12 - s1*s2*scale;
2038 double denom2 = (s11 - s1*s1*scale)*(s22 - s2*s2*scale);
2039 result = std::abs(denom2) > DBL_EPSILON ? num/std::sqrt(denom2) : 1.;
2041 else if( method == CV_COMP_BHATTACHARYYA )
2044 s1 = fabs(s1) > FLT_EPSILON ? 1./std::sqrt(s1) : 1.;
2045 result = std::sqrt(std::max(1. - result*s1, 0.));
2052 double cv::compareHist( const SparseMat& H1, const SparseMat& H2, int method )
2055 int i, dims = H1.dims();
2057 CV_Assert( dims > 0 && dims == H2.dims() && H1.type() == H2.type() && H1.type() == CV_32F );
2058 for( i = 0; i < dims; i++ )
2059 CV_Assert( H1.size(i) == H2.size(i) );
2061 const SparseMat *PH1 = &H1, *PH2 = &H2;
2062 if( PH1->nzcount() > PH2->nzcount() && method != CV_COMP_CHISQR )
2063 std::swap(PH1, PH2);
2065 SparseMatConstIterator it = PH1->begin();
2066 int N1 = (int)PH1->nzcount(), N2 = (int)PH2->nzcount();
2068 if( method == CV_COMP_CHISQR )
2070 for( i = 0; i < N1; i++, ++it )
2072 float v1 = it.value<float>();
2073 const SparseMat::Node* node = it.node();
2074 float v2 = PH2->value<float>(node->idx, (size_t*)&node->hashval);
2077 if( fabs(b) > DBL_EPSILON )
2081 else if( method == CV_COMP_CORREL )
2083 double s1 = 0, s2 = 0, s11 = 0, s12 = 0, s22 = 0;
2085 for( i = 0; i < N1; i++, ++it )
2087 double v1 = it.value<float>();
2088 const SparseMat::Node* node = it.node();
2089 s12 += v1*PH2->value<float>(node->idx, (size_t*)&node->hashval);
2095 for( i = 0; i < N2; i++, ++it )
2097 double v2 = it.value<float>();
2103 for( i = 0; i < H1.dims(); i++ )
2104 total *= H1.size(i);
2105 double scale = 1./total;
2106 double num = s12 - s1*s2*scale;
2107 double denom2 = (s11 - s1*s1*scale)*(s22 - s2*s2*scale);
2108 result = std::abs(denom2) > DBL_EPSILON ? num/std::sqrt(denom2) : 1.;
2110 else if( method == CV_COMP_INTERSECT )
2112 for( i = 0; i < N1; i++, ++it )
2114 float v1 = it.value<float>();
2115 const SparseMat::Node* node = it.node();
2116 float v2 = PH2->value<float>(node->idx, (size_t*)&node->hashval);
2118 result += std::min(v1, v2);
2121 else if( method == CV_COMP_BHATTACHARYYA )
2123 double s1 = 0, s2 = 0;
2125 for( i = 0; i < N1; i++, ++it )
2127 double v1 = it.value<float>();
2128 const SparseMat::Node* node = it.node();
2129 double v2 = PH2->value<float>(node->idx, (size_t*)&node->hashval);
2130 result += std::sqrt(v1*v2);
2135 for( i = 0; i < N2; i++, ++it )
2136 s2 += it.value<float>();
2139 s1 = fabs(s1) > FLT_EPSILON ? 1./std::sqrt(s1) : 1.;
2140 result = std::sqrt(std::max(1. - result*s1, 0.));
2143 CV_Error( CV_StsBadArg, "Unknown comparison method" );
2149 const int CV_HIST_DEFAULT_TYPE = CV_32F;
2151 /* Creates new histogram */
2153 cvCreateHist( int dims, int *sizes, CvHistType type, float** ranges, int uniform )
2155 CvHistogram *hist = 0;
2157 if( (unsigned)dims > CV_MAX_DIM )
2158 CV_Error( CV_BadOrder, "Number of dimensions is out of range" );
2161 CV_Error( CV_HeaderIsNull, "Null <sizes> pointer" );
2163 hist = (CvHistogram *)cvAlloc( sizeof( CvHistogram ));
2164 hist->type = CV_HIST_MAGIC_VAL + ((int)type & 1);
2165 if (uniform) hist->type|= CV_HIST_UNIFORM_FLAG;
2168 if( type == CV_HIST_ARRAY )
2170 hist->bins = cvInitMatNDHeader( &hist->mat, dims, sizes,
2171 CV_HIST_DEFAULT_TYPE );
2172 cvCreateData( hist->bins );
2174 else if( type == CV_HIST_SPARSE )
2175 hist->bins = cvCreateSparseMat( dims, sizes, CV_HIST_DEFAULT_TYPE );
2177 CV_Error( CV_StsBadArg, "Invalid histogram type" );
2180 cvSetHistBinRanges( hist, ranges, uniform );
2186 /* Creates histogram wrapping header for given array */
2187 CV_IMPL CvHistogram*
2188 cvMakeHistHeaderForArray( int dims, int *sizes, CvHistogram *hist,
2189 float *data, float **ranges, int uniform )
2192 CV_Error( CV_StsNullPtr, "Null histogram header pointer" );
2195 CV_Error( CV_StsNullPtr, "Null data pointer" );
2198 hist->type = CV_HIST_MAGIC_VAL;
2199 hist->bins = cvInitMatNDHeader( &hist->mat, dims, sizes, CV_HIST_DEFAULT_TYPE, data );
2204 CV_Error( CV_StsBadArg, "Only uniform bin ranges can be used here "
2205 "(to avoid memory allocation)" );
2206 cvSetHistBinRanges( hist, ranges, uniform );
2214 cvReleaseHist( CvHistogram **hist )
2217 CV_Error( CV_StsNullPtr, "" );
2221 CvHistogram* temp = *hist;
2223 if( !CV_IS_HIST(temp))
2224 CV_Error( CV_StsBadArg, "Invalid histogram header" );
2227 if( CV_IS_SPARSE_HIST( temp ))
2228 cvReleaseSparseMat( (CvSparseMat**)&temp->bins );
2231 cvReleaseData( temp->bins );
2236 cvFree( &temp->thresh2 );
2242 cvClearHist( CvHistogram *hist )
2244 if( !CV_IS_HIST(hist) )
2245 CV_Error( CV_StsBadArg, "Invalid histogram header" );
2246 cvZero( hist->bins );
2250 // Clears histogram bins that are below than threshold
2252 cvThreshHist( CvHistogram* hist, double thresh )
2254 if( !CV_IS_HIST(hist) )
2255 CV_Error( CV_StsBadArg, "Invalid histogram header" );
2257 if( !CV_IS_SPARSE_MAT(hist->bins) )
2260 cvGetMat( hist->bins, &mat, 0, 1 );
2261 cvThreshold( &mat, &mat, thresh, 0, CV_THRESH_TOZERO );
2265 CvSparseMat* mat = (CvSparseMat*)hist->bins;
2266 CvSparseMatIterator iterator;
2269 for( node = cvInitSparseMatIterator( mat, &iterator );
2270 node != 0; node = cvGetNextSparseNode( &iterator ))
2272 float* val = (float*)CV_NODE_VAL( mat, node );
2273 if( *val <= thresh )
2280 // Normalizes histogram (make sum of the histogram bins == factor)
2282 cvNormalizeHist( CvHistogram* hist, double factor )
2286 if( !CV_IS_HIST(hist) )
2287 CV_Error( CV_StsBadArg, "Invalid histogram header" );
2289 if( !CV_IS_SPARSE_HIST(hist) )
2292 cvGetMat( hist->bins, &mat, 0, 1 );
2293 sum = cvSum( &mat ).val[0];
2294 if( fabs(sum) < DBL_EPSILON )
2296 cvScale( &mat, &mat, factor/sum, 0 );
2300 CvSparseMat* mat = (CvSparseMat*)hist->bins;
2301 CvSparseMatIterator iterator;
2305 for( node = cvInitSparseMatIterator( mat, &iterator );
2306 node != 0; node = cvGetNextSparseNode( &iterator ))
2308 sum += *(float*)CV_NODE_VAL(mat,node);
2311 if( fabs(sum) < DBL_EPSILON )
2313 scale = (float)(factor/sum);
2315 for( node = cvInitSparseMatIterator( mat, &iterator );
2316 node != 0; node = cvGetNextSparseNode( &iterator ))
2318 *(float*)CV_NODE_VAL(mat,node) *= scale;
2324 // Retrieves histogram global min, max and their positions
2326 cvGetMinMaxHistValue( const CvHistogram* hist,
2327 float *value_min, float* value_max,
2328 int* idx_min, int* idx_max )
2330 double minVal, maxVal;
2331 int dims, size[CV_MAX_DIM];
2333 if( !CV_IS_HIST(hist) )
2334 CV_Error( CV_StsBadArg, "Invalid histogram header" );
2336 dims = cvGetDims( hist->bins, size );
2338 if( !CV_IS_SPARSE_HIST(hist) )
2341 CvPoint minPt, maxPt;
2343 cvGetMat( hist->bins, &mat, 0, 1 );
2344 cvMinMaxLoc( &mat, &minVal, &maxVal, &minPt, &maxPt );
2349 *idx_min = minPt.y + minPt.x;
2351 *idx_max = maxPt.y + maxPt.x;
2353 else if( dims == 2 )
2356 idx_min[0] = minPt.y, idx_min[1] = minPt.x;
2358 idx_max[0] = maxPt.y, idx_max[1] = maxPt.x;
2360 else if( idx_min || idx_max )
2362 int imin = minPt.y*mat.cols + minPt.x;
2363 int imax = maxPt.y*mat.cols + maxPt.x;
2365 for(int i = dims - 1; i >= 0; i-- )
2369 int t = imin / size[i];
2370 idx_min[i] = imin - t*size[i];
2376 int t = imax / size[i];
2377 idx_max[i] = imax - t*size[i];
2385 CvSparseMat* mat = (CvSparseMat*)hist->bins;
2386 CvSparseMatIterator iterator;
2390 CvSparseNode* minNode = 0;
2391 CvSparseNode* maxNode = 0;
2392 const int *_idx_min = 0, *_idx_max = 0;
2395 for( node = cvInitSparseMatIterator( mat, &iterator );
2396 node != 0; node = cvGetNextSparseNode( &iterator ))
2398 int value = *(int*)CV_NODE_VAL(mat,node);
2399 value = CV_TOGGLE_FLT(value);
2415 _idx_min = CV_NODE_IDX(mat,minNode);
2416 _idx_max = CV_NODE_IDX(mat,maxNode);
2417 m.i = CV_TOGGLE_FLT(minv); minVal = m.f;
2418 m.i = CV_TOGGLE_FLT(maxv); maxVal = m.f;
2422 minVal = maxVal = 0;
2425 for(int i = 0; i < dims; i++ )
2428 idx_min[i] = _idx_min ? _idx_min[i] : -1;
2430 idx_max[i] = _idx_max ? _idx_max[i] : -1;
2435 *value_min = (float)minVal;
2438 *value_max = (float)maxVal;
2442 // Compares two histograms using one of a few methods
2444 cvCompareHist( const CvHistogram* hist1,
2445 const CvHistogram* hist2,
2449 int size1[CV_MAX_DIM], size2[CV_MAX_DIM], total = 1;
2451 if( !CV_IS_HIST(hist1) || !CV_IS_HIST(hist2) )
2452 CV_Error( CV_StsBadArg, "Invalid histogram header[s]" );
2454 if( CV_IS_SPARSE_MAT(hist1->bins) != CV_IS_SPARSE_MAT(hist2->bins))
2455 CV_Error(CV_StsUnmatchedFormats, "One of histograms is sparse and other is not");
2457 if( !CV_IS_SPARSE_MAT(hist1->bins) )
2459 cv::Mat H1((const CvMatND*)hist1->bins), H2((const CvMatND*)hist2->bins);
2460 return cv::compareHist(H1, H2, method);
2463 int dims1 = cvGetDims( hist1->bins, size1 );
2464 int dims2 = cvGetDims( hist2->bins, size2 );
2466 if( dims1 != dims2 )
2467 CV_Error( CV_StsUnmatchedSizes,
2468 "The histograms have different numbers of dimensions" );
2470 for( i = 0; i < dims1; i++ )
2472 if( size1[i] != size2[i] )
2473 CV_Error( CV_StsUnmatchedSizes, "The histograms have different sizes" );
2478 CvSparseMat* mat1 = (CvSparseMat*)(hist1->bins);
2479 CvSparseMat* mat2 = (CvSparseMat*)(hist2->bins);
2480 CvSparseMatIterator iterator;
2481 CvSparseNode *node1, *node2;
2483 if( mat1->heap->active_count > mat2->heap->active_count && method != CV_COMP_CHISQR )
2486 CV_SWAP( mat1, mat2, t );
2489 if( method == CV_COMP_CHISQR )
2491 for( node1 = cvInitSparseMatIterator( mat1, &iterator );
2492 node1 != 0; node1 = cvGetNextSparseNode( &iterator ))
2494 double v1 = *(float*)CV_NODE_VAL(mat1,node1);
2495 uchar* node2_data = cvPtrND( mat2, CV_NODE_IDX(mat1,node1), 0, 0, &node1->hashval );
2496 double v2 = node2_data ? *(float*)node2_data : 0.f;
2499 if( fabs(b) > DBL_EPSILON )
2503 else if( method == CV_COMP_CORREL )
2505 double s1 = 0, s11 = 0;
2506 double s2 = 0, s22 = 0;
2508 double num, denom2, scale = 1./total;
2510 for( node1 = cvInitSparseMatIterator( mat1, &iterator );
2511 node1 != 0; node1 = cvGetNextSparseNode( &iterator ))
2513 double v1 = *(float*)CV_NODE_VAL(mat1,node1);
2514 uchar* node2_data = cvPtrND( mat2, CV_NODE_IDX(mat1,node1),
2515 0, 0, &node1->hashval );
2518 double v2 = *(float*)node2_data;
2525 for( node2 = cvInitSparseMatIterator( mat2, &iterator );
2526 node2 != 0; node2 = cvGetNextSparseNode( &iterator ))
2528 double v2 = *(float*)CV_NODE_VAL(mat2,node2);
2533 num = s12 - s1*s2*scale;
2534 denom2 = (s11 - s1*s1*scale)*(s22 - s2*s2*scale);
2535 result = fabs(denom2) > DBL_EPSILON ? num/sqrt(denom2) : 1;
2537 else if( method == CV_COMP_INTERSECT )
2539 for( node1 = cvInitSparseMatIterator( mat1, &iterator );
2540 node1 != 0; node1 = cvGetNextSparseNode( &iterator ))
2542 float v1 = *(float*)CV_NODE_VAL(mat1,node1);
2543 uchar* node2_data = cvPtrND( mat2, CV_NODE_IDX(mat1,node1),
2544 0, 0, &node1->hashval );
2547 float v2 = *(float*)node2_data;
2555 else if( method == CV_COMP_BHATTACHARYYA )
2557 double s1 = 0, s2 = 0;
2559 for( node1 = cvInitSparseMatIterator( mat1, &iterator );
2560 node1 != 0; node1 = cvGetNextSparseNode( &iterator ))
2562 double v1 = *(float*)CV_NODE_VAL(mat1,node1);
2563 uchar* node2_data = cvPtrND( mat2, CV_NODE_IDX(mat1,node1),
2564 0, 0, &node1->hashval );
2568 double v2 = *(float*)node2_data;
2569 result += sqrt(v1 * v2);
2573 for( node1 = cvInitSparseMatIterator( mat2, &iterator );
2574 node1 != 0; node1 = cvGetNextSparseNode( &iterator ))
2576 double v2 = *(float*)CV_NODE_VAL(mat2,node1);
2581 s1 = fabs(s1) > FLT_EPSILON ? 1./sqrt(s1) : 1.;
2582 result = 1. - result*s1;
2583 result = sqrt(MAX(result,0.));
2586 CV_Error( CV_StsBadArg, "Unknown comparison method" );
2591 // copies one histogram to another
2593 cvCopyHist( const CvHistogram* src, CvHistogram** _dst )
2596 CV_Error( CV_StsNullPtr, "Destination double pointer is NULL" );
2598 CvHistogram* dst = *_dst;
2600 if( !CV_IS_HIST(src) || (dst && !CV_IS_HIST(dst)) )
2601 CV_Error( CV_StsBadArg, "Invalid histogram header[s]" );
2604 int size1[CV_MAX_DIM];
2605 bool is_sparse = CV_IS_SPARSE_MAT(src->bins);
2606 int dims1 = cvGetDims( src->bins, size1 );
2608 if( dst && (is_sparse == CV_IS_SPARSE_MAT(dst->bins)))
2610 int size2[CV_MAX_DIM];
2611 int dims2 = cvGetDims( dst->bins, size2 );
2613 if( dims1 == dims2 )
2617 for( i = 0; i < dims1; i++ )
2619 if( size1[i] != size2[i] )
2629 cvReleaseHist( _dst );
2630 dst = cvCreateHist( dims1, size1, !is_sparse ? CV_HIST_ARRAY : CV_HIST_SPARSE, 0, 0 );
2634 if( CV_HIST_HAS_RANGES( src ))
2636 float* ranges[CV_MAX_DIM];
2639 if( CV_IS_UNIFORM_HIST( src ))
2641 for( int i = 0; i < dims1; i++ )
2642 ranges[i] = (float*)src->thresh[i];
2648 thresh = src->thresh2;
2651 cvSetHistBinRanges( dst, thresh, CV_IS_UNIFORM_HIST(src));
2654 cvCopy( src->bins, dst->bins );
2658 // Sets a value range for every histogram bin
2660 cvSetHistBinRanges( CvHistogram* hist, float** ranges, int uniform )
2662 int dims, size[CV_MAX_DIM], total = 0;
2666 CV_Error( CV_StsNullPtr, "NULL ranges pointer" );
2668 if( !CV_IS_HIST(hist) )
2669 CV_Error( CV_StsBadArg, "Invalid histogram header" );
2671 dims = cvGetDims( hist->bins, size );
2672 for( i = 0; i < dims; i++ )
2677 for( i = 0; i < dims; i++ )
2680 CV_Error( CV_StsNullPtr, "One of <ranges> elements is NULL" );
2681 hist->thresh[i][0] = ranges[i][0];
2682 hist->thresh[i][1] = ranges[i][1];
2685 hist->type |= CV_HIST_UNIFORM_FLAG + CV_HIST_RANGES_FLAG;
2691 if( !hist->thresh2 )
2693 hist->thresh2 = (float**)cvAlloc(
2694 dims*sizeof(hist->thresh2[0])+
2695 total*sizeof(hist->thresh2[0][0]));
2697 dim_ranges = (float*)(hist->thresh2 + dims);
2699 for( i = 0; i < dims; i++ )
2701 float val0 = -FLT_MAX;
2704 CV_Error( CV_StsNullPtr, "One of <ranges> elements is NULL" );
2706 for( j = 0; j <= size[i]; j++ )
2708 float val = ranges[i][j];
2710 CV_Error(CV_StsOutOfRange, "Bin ranges should go in ascenting order");
2711 val0 = dim_ranges[j] = val;
2714 hist->thresh2[i] = dim_ranges;
2715 dim_ranges += size[i] + 1;
2718 hist->type |= CV_HIST_RANGES_FLAG;
2719 hist->type &= ~CV_HIST_UNIFORM_FLAG;
2725 cvCalcArrHist( CvArr** img, CvHistogram* hist, int accumulate, const CvArr* mask )
2727 if( !CV_IS_HIST(hist))
2728 CV_Error( CV_StsBadArg, "Bad histogram pointer" );
2731 CV_Error( CV_StsNullPtr, "Null double array pointer" );
2733 int size[CV_MAX_DIM];
2734 int i, dims = cvGetDims( hist->bins, size);
2735 bool uniform = CV_IS_UNIFORM_HIST(hist);
2737 cv::vector<cv::Mat> images(dims);
2738 for( i = 0; i < dims; i++ )
2739 images[i] = cv::cvarrToMat(img[i]);
2743 _mask = cv::cvarrToMat(mask);
2745 const float* uranges[CV_MAX_DIM] = {0};
2746 const float** ranges = 0;
2748 if( hist->type & CV_HIST_RANGES_FLAG )
2750 ranges = (const float**)hist->thresh2;
2753 for( i = 0; i < dims; i++ )
2754 uranges[i] = &hist->thresh[i][0];
2759 if( !CV_IS_SPARSE_HIST(hist) )
2761 cv::Mat H((const CvMatND*)hist->bins);
2762 cv::calcHist( &images[0], (int)images.size(), 0, _mask,
2763 H, cvGetDims(hist->bins), H.size, ranges, uniform, accumulate != 0 );
2767 CvSparseMat* sparsemat = (CvSparseMat*)hist->bins;
2770 cvZero( hist->bins );
2771 cv::SparseMat sH(sparsemat);
2772 cv::calcHist( &images[0], (int)images.size(), 0, _mask, sH, sH.dims(),
2773 sH.dims() > 0 ? sH.hdr->size : 0, ranges, uniform, accumulate != 0, true );
2776 cvZero( sparsemat );
2778 cv::SparseMatConstIterator it = sH.begin();
2779 int nz = (int)sH.nzcount();
2780 for( i = 0; i < nz; i++, ++it )
2781 *(float*)cvPtrND(sparsemat, it.node()->idx, 0, -2) = (float)*(const int*)it.ptr;
2787 cvCalcArrBackProject( CvArr** img, CvArr* dst, const CvHistogram* hist )
2789 if( !CV_IS_HIST(hist))
2790 CV_Error( CV_StsBadArg, "Bad histogram pointer" );
2793 CV_Error( CV_StsNullPtr, "Null double array pointer" );
2795 int size[CV_MAX_DIM];
2796 int i, dims = cvGetDims( hist->bins, size );
2798 bool uniform = CV_IS_UNIFORM_HIST(hist);
2799 const float* uranges[CV_MAX_DIM] = {0};
2800 const float** ranges = 0;
2802 if( hist->type & CV_HIST_RANGES_FLAG )
2804 ranges = (const float**)hist->thresh2;
2807 for( i = 0; i < dims; i++ )
2808 uranges[i] = &hist->thresh[i][0];
2813 cv::vector<cv::Mat> images(dims);
2814 for( i = 0; i < dims; i++ )
2815 images[i] = cv::cvarrToMat(img[i]);
2817 cv::Mat _dst = cv::cvarrToMat(dst);
2819 CV_Assert( _dst.size() == images[0].size() && _dst.depth() == images[0].depth() );
2821 if( !CV_IS_SPARSE_HIST(hist) )
2823 cv::Mat H((const CvMatND*)hist->bins);
2824 cv::calcBackProject( &images[0], (int)images.size(),
2825 0, H, _dst, ranges, 1, uniform );
2829 cv::SparseMat sH((const CvSparseMat*)hist->bins);
2830 cv::calcBackProject( &images[0], (int)images.size(),
2831 0, sH, _dst, ranges, 1, uniform );
2836 ////////////////////// B A C K P R O J E C T P A T C H /////////////////////////
2839 cvCalcArrBackProjectPatch( CvArr** arr, CvArr* dst, CvSize patch_size, CvHistogram* hist,
2840 int method, double norm_factor )
2842 CvHistogram* model = 0;
2844 IplImage imgstub[CV_MAX_DIM], *img[CV_MAX_DIM];
2846 CvMat dststub, *dstmat;
2851 if( !CV_IS_HIST(hist))
2852 CV_Error( CV_StsBadArg, "Bad histogram pointer" );
2855 CV_Error( CV_StsNullPtr, "Null double array pointer" );
2857 if( norm_factor <= 0 )
2858 CV_Error( CV_StsOutOfRange,
2859 "Bad normalization factor (set it to 1.0 if unsure)" );
2861 if( patch_size.width <= 0 || patch_size.height <= 0 )
2862 CV_Error( CV_StsBadSize, "The patch width and height must be positive" );
2864 dims = cvGetDims( hist->bins );
2865 cvNormalizeHist( hist, norm_factor );
2867 for( i = 0; i < dims; i++ )
2870 mat = cvGetMat( arr[i], &stub, 0, 0 );
2871 img[i] = cvGetImage( mat, &imgstub[i] );
2875 dstmat = cvGetMat( dst, &dststub, 0, 0 );
2876 if( CV_MAT_TYPE( dstmat->type ) != CV_32FC1 )
2877 CV_Error( CV_StsUnsupportedFormat, "Resultant image must have 32fC1 type" );
2879 if( dstmat->cols != img[0]->width - patch_size.width + 1 ||
2880 dstmat->rows != img[0]->height - patch_size.height + 1 )
2881 CV_Error( CV_StsUnmatchedSizes,
2882 "The output map must be (W-w+1 x H-h+1), "
2883 "where the input images are (W x H) each and the patch is (w x h)" );
2885 cvCopyHist( hist, &model );
2887 size = cvGetMatSize(dstmat);
2889 roi.width = patch_size.width;
2890 roi.height = patch_size.height;
2892 for( y = 0; y < size.height; y++ )
2894 for( x = 0; x < size.width; x++ )
2900 cvCalcHist( img, model );
2901 cvNormalizeHist( model, norm_factor );
2902 result = cvCompareHist( model, hist, method );
2903 CV_MAT_ELEM( *dstmat, float, y, x ) = (float)result;
2907 cvReleaseHist( &model );
2911 // Calculates Bayes probabilistic histograms
2913 cvCalcBayesianProb( CvHistogram** src, int count, CvHistogram** dst )
2918 CV_Error( CV_StsNullPtr, "NULL histogram array pointer" );
2921 CV_Error( CV_StsOutOfRange, "Too small number of histograms" );
2923 for( i = 0; i < count; i++ )
2925 if( !CV_IS_HIST(src[i]) || !CV_IS_HIST(dst[i]) )
2926 CV_Error( CV_StsBadArg, "Invalid histogram header" );
2928 if( !CV_IS_MATND(src[i]->bins) || !CV_IS_MATND(dst[i]->bins) )
2929 CV_Error( CV_StsBadArg, "The function supports dense histograms only" );
2932 cvZero( dst[0]->bins );
2933 // dst[0] = src[0] + ... + src[count-1]
2934 for( i = 0; i < count; i++ )
2935 cvAdd( src[i]->bins, dst[0]->bins, dst[0]->bins );
2937 cvDiv( 0, dst[0]->bins, dst[0]->bins );
2939 // dst[i] = src[i]*(1/dst[0])
2940 for( i = count - 1; i >= 0; i-- )
2941 cvMul( src[i]->bins, dst[0]->bins, dst[i]->bins );
2946 cvCalcProbDensity( const CvHistogram* hist, const CvHistogram* hist_mask,
2947 CvHistogram* hist_dens, double scale )
2950 CV_Error( CV_StsOutOfRange, "scale must be positive" );
2952 if( !CV_IS_HIST(hist) || !CV_IS_HIST(hist_mask) || !CV_IS_HIST(hist_dens) )
2953 CV_Error( CV_StsBadArg, "Invalid histogram pointer[s]" );
2956 CvArr* arrs[] = { hist->bins, hist_mask->bins, hist_dens->bins };
2958 CvNArrayIterator iterator;
2960 cvInitNArrayIterator( 3, arrs, 0, stubs, &iterator );
2962 if( CV_MAT_TYPE(iterator.hdr[0]->type) != CV_32FC1 )
2963 CV_Error( CV_StsUnsupportedFormat, "All histograms must have 32fC1 type" );
2967 const float* srcdata = (const float*)(iterator.ptr[0]);
2968 const float* maskdata = (const float*)(iterator.ptr[1]);
2969 float* dstdata = (float*)(iterator.ptr[2]);
2972 for( i = 0; i < iterator.size.width; i++ )
2974 float s = srcdata[i];
2975 float m = maskdata[i];
2976 if( s > FLT_EPSILON )
2978 dstdata[i] = (float)(m*scale/s);
2980 dstdata[i] = (float)scale;
2982 dstdata[i] = (float)0;
2985 while( cvNextNArraySlice( &iterator ));
2989 class EqualizeHistCalcHist_Invoker : public cv::ParallelLoopBody
2992 enum {HIST_SZ = 256};
2994 EqualizeHistCalcHist_Invoker(cv::Mat& src, int* histogram, cv::Mutex* histogramLock)
2995 : src_(src), globalHistogram_(histogram), histogramLock_(histogramLock)
2998 void operator()( const cv::Range& rowRange ) const
3000 int localHistogram[HIST_SZ] = {0, };
3002 const size_t sstep = src_.step;
3004 int width = src_.cols;
3005 int height = rowRange.end - rowRange.start;
3007 if (src_.isContinuous())
3013 for (const uchar* ptr = src_.ptr<uchar>(rowRange.start); height--; ptr += sstep)
3016 for (; x <= width - 4; x += 4)
3018 int t0 = ptr[x], t1 = ptr[x+1];
3019 localHistogram[t0]++; localHistogram[t1]++;
3020 t0 = ptr[x+2]; t1 = ptr[x+3];
3021 localHistogram[t0]++; localHistogram[t1]++;
3024 for (; x < width; ++x)
3025 localHistogram[ptr[x]]++;
3028 cv::AutoLock lock(*histogramLock_);
3030 for( int i = 0; i < HIST_SZ; i++ )
3031 globalHistogram_[i] += localHistogram[i];
3034 static bool isWorthParallel( const cv::Mat& src )
3036 return ( src.total() >= 640*480 );
3040 EqualizeHistCalcHist_Invoker& operator=(const EqualizeHistCalcHist_Invoker&);
3043 int* globalHistogram_;
3044 cv::Mutex* histogramLock_;
3047 class EqualizeHistLut_Invoker : public cv::ParallelLoopBody
3050 EqualizeHistLut_Invoker( cv::Mat& src, cv::Mat& dst, int* lut )
3056 void operator()( const cv::Range& rowRange ) const
3058 const size_t sstep = src_.step;
3059 const size_t dstep = dst_.step;
3061 int width = src_.cols;
3062 int height = rowRange.end - rowRange.start;
3065 if (src_.isContinuous() && dst_.isContinuous())
3071 const uchar* sptr = src_.ptr<uchar>(rowRange.start);
3072 uchar* dptr = dst_.ptr<uchar>(rowRange.start);
3074 for (; height--; sptr += sstep, dptr += dstep)
3077 for (; x <= width - 4; x += 4)
3083 dptr[x] = (uchar)x0;
3084 dptr[x+1] = (uchar)x1;
3090 dptr[x+2] = (uchar)x0;
3091 dptr[x+3] = (uchar)x1;
3094 for (; x < width; ++x)
3095 dptr[x] = (uchar)lut[sptr[x]];
3099 static bool isWorthParallel( const cv::Mat& src )
3101 return ( src.total() >= 640*480 );
3105 EqualizeHistLut_Invoker& operator=(const EqualizeHistLut_Invoker&);
3112 CV_IMPL void cvEqualizeHist( const CvArr* srcarr, CvArr* dstarr )
3114 cv::equalizeHist(cv::cvarrToMat(srcarr), cv::cvarrToMat(dstarr));
3117 void cv::equalizeHist( InputArray _src, OutputArray _dst )
3119 Mat src = _src.getMat();
3120 CV_Assert( src.type() == CV_8UC1 );
3122 _dst.create( src.size(), src.type() );
3123 Mat dst = _dst.getMat();
3128 Mutex histogramLockInstance;
3130 const int hist_sz = EqualizeHistCalcHist_Invoker::HIST_SZ;
3131 int hist[hist_sz] = {0,};
3134 EqualizeHistCalcHist_Invoker calcBody(src, hist, &histogramLockInstance);
3135 EqualizeHistLut_Invoker lutBody(src, dst, lut);
3136 cv::Range heightRange(0, src.rows);
3138 if(EqualizeHistCalcHist_Invoker::isWorthParallel(src))
3139 parallel_for_(heightRange, calcBody);
3141 calcBody(heightRange);
3144 while (!hist[i]) ++i;
3146 int total = (int)src.total();
3147 if (hist[i] == total)
3153 float scale = (hist_sz - 1.f)/(total - hist[i]);
3156 for (lut[i++] = 0; i < hist_sz; ++i)
3159 lut[i] = saturate_cast<uchar>(sum * scale);
3162 if(EqualizeHistLut_Invoker::isWorthParallel(src))
3163 parallel_for_(heightRange, lutBody);
3165 lutBody(heightRange);
3168 // ----------------------------------------------------------------------
3170 /* Implementation of RTTI and Generic Functions for CvHistogram */
3171 #define CV_TYPE_NAME_HIST "opencv-hist"
3173 static int icvIsHist( const void * ptr )
3175 return CV_IS_HIST( ((CvHistogram*)ptr) );
3178 static CvHistogram * icvCloneHist( const CvHistogram * src )
3180 CvHistogram * dst=NULL;
3181 cvCopyHist(src, &dst);
3185 static void *icvReadHist( CvFileStorage * fs, CvFileNode * node )
3187 CvHistogram * h = 0;
3190 int have_ranges = 0;
3192 h = (CvHistogram *)cvAlloc( sizeof(CvHistogram) );
3194 type = cvReadIntByName( fs, node, "type", 0 );
3195 is_uniform = cvReadIntByName( fs, node, "is_uniform", 0 );
3196 have_ranges = cvReadIntByName( fs, node, "have_ranges", 0 );
3197 h->type = CV_HIST_MAGIC_VAL | type |
3198 (is_uniform ? CV_HIST_UNIFORM_FLAG : 0) |
3199 (have_ranges ? CV_HIST_RANGES_FLAG : 0);
3201 if(type == CV_HIST_ARRAY)
3203 // read histogram bins
3204 CvMatND* mat = (CvMatND*)cvReadByName( fs, node, "mat" );
3205 int i, sizes[CV_MAX_DIM];
3207 if(!CV_IS_MATND(mat))
3208 CV_Error( CV_StsError, "Expected CvMatND");
3210 for(i=0; i<mat->dims; i++)
3211 sizes[i] = mat->dim[i].size;
3213 cvInitMatNDHeader( &(h->mat), mat->dims, sizes, mat->type, mat->data.ptr );
3214 h->bins = &(h->mat);
3216 // take ownership of refcount pointer as well
3217 h->mat.refcount = mat->refcount;
3219 // increase refcount so freeing temp header doesn't free data
3220 cvIncRefData( mat );
3222 // free temporary header
3223 cvReleaseMatND( &mat );
3227 h->bins = cvReadByName( fs, node, "bins" );
3228 if(!CV_IS_SPARSE_MAT(h->bins)){
3229 CV_Error( CV_StsError, "Unknown Histogram type");
3236 int i, dims, size[CV_MAX_DIM], total = 0;
3238 CvFileNode * thresh_node;
3240 dims = cvGetDims( h->bins, size );
3241 for( i = 0; i < dims; i++ )
3244 thresh_node = cvGetFileNodeByName( fs, node, "thresh" );
3246 CV_Error( CV_StsError, "'thresh' node is missing");
3247 cvStartReadRawData( fs, thresh_node, &reader );
3251 for(i=0; i<dims; i++)
3252 cvReadRawDataSlice( fs, &reader, 2, h->thresh[i], "f" );
3258 h->thresh2 = (float**)cvAlloc(
3259 dims*sizeof(h->thresh2[0])+
3260 total*sizeof(h->thresh2[0][0]));
3261 dim_ranges = (float*)(h->thresh2 + dims);
3262 for(i=0; i < dims; i++)
3264 h->thresh2[i] = dim_ranges;
3265 cvReadRawDataSlice( fs, &reader, size[i]+1, dim_ranges, "f" );
3266 dim_ranges += size[i] + 1;
3274 static void icvWriteHist( CvFileStorage* fs, const char* name,
3275 const void* struct_ptr, CvAttrList /*attributes*/ )
3277 const CvHistogram * hist = (const CvHistogram *) struct_ptr;
3278 int sizes[CV_MAX_DIM];
3281 int is_uniform, have_ranges;
3283 cvStartWriteStruct( fs, name, CV_NODE_MAP, CV_TYPE_NAME_HIST );
3285 is_uniform = (CV_IS_UNIFORM_HIST(hist) ? 1 : 0);
3286 have_ranges = (hist->type & CV_HIST_RANGES_FLAG ? 1 : 0);
3288 cvWriteInt( fs, "type", (hist->type & 1) );
3289 cvWriteInt( fs, "is_uniform", is_uniform );
3290 cvWriteInt( fs, "have_ranges", have_ranges );
3291 if(!CV_IS_SPARSE_HIST(hist))
3292 cvWrite( fs, "mat", &(hist->mat) );
3294 cvWrite( fs, "bins", hist->bins );
3298 dims = cvGetDims( hist->bins, sizes );
3299 cvStartWriteStruct( fs, "thresh", CV_NODE_SEQ + CV_NODE_FLOW );
3301 for(i=0; i<dims; i++){
3302 cvWriteRawData( fs, hist->thresh[i], 2, "f" );
3306 for(i=0; i<dims; i++){
3307 cvWriteRawData( fs, hist->thresh2[i], sizes[i]+1, "f" );
3310 cvEndWriteStruct( fs );
3313 cvEndWriteStruct( fs );
3317 CvType hist_type( CV_TYPE_NAME_HIST, icvIsHist, (CvReleaseFunc)cvReleaseHist,
3318 icvReadHist, icvWriteHist, (CvCloneFunc)icvCloneHist );