Move the sources to trunk
[opencv] / ml / src / mlestimate.cpp
1 /*M///////////////////////////////////////////////////////////////////////////////////////
2 //
3 //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
4 //
5 //  By downloading, copying, installing or using the software you agree to this license.
6 //  If you do not agree to this license, do not download, install,
7 //  copy or use the software.
8 //
9 //
10 //                        Intel License Agreement
11 //
12 // Copyright (C) 2000, Intel Corporation, all rights reserved.
13 // Third party copyrights are property of their respective owners.
14 //
15 // Redistribution and use in source and binary forms, with or without modification,
16 // are permitted provided that the following conditions are met:
17 //
18 //   * Redistribution's of source code must retain the above copyright notice,
19 //     this list of conditions and the following disclaimer.
20 //
21 //   * Redistribution's in binary form must reproduce the above copyright notice,
22 //     this list of conditions and the following disclaimer in the documentation
23 //     and/or other materials provided with the distribution.
24 //
25 //   * The name of Intel Corporation may not be used to endorse or promote products
26 //     derived from this software without specific prior written permission.
27 //
28 // This software is provided by the copyright holders and contributors "as is" and
29 // any express or implied warranties, including, but not limited to, the implied
30 // warranties of merchantability and fitness for a particular purpose are disclaimed.
31 // In no event shall the Intel Corporation or contributors be liable for any direct,
32 // indirect, incidental, special, exemplary, or consequential damages
33 // (including, but not limited to, procurement of substitute goods or services;
34 // loss of use, data, or profits; or business interruption) however caused
35 // and on any theory of liability, whether in contract, strict liability,
36 // or tort (including negligence or otherwise) arising in any way out of
37 // the use of this software, even if advised of the possibility of such damage.
38 //
39 //M*/
40
41 #include "_ml.h"
42
43 #if 0
44
45 ML_IMPL int
46 icvCmpIntegers (const void* a, const void* b) {return *(const int*)a - *(const int*)b;}
47
48 /****************************************************************************************\
49 *                    Cross-validation algorithms realizations                            *
50 \****************************************************************************************/
51
52 // Return pointer to trainIdx. Function DOES NOT FILL this matrix!
53 ML_IMPL
54 const CvMat* cvCrossValGetTrainIdxMatrix (const CvStatModel* estimateModel)
55 {
56     CvMat* result = NULL;
57
58         CV_FUNCNAME ("cvCrossValGetTrainIdxMatrix");
59         __BEGIN__
60
61     if (!CV_IS_CROSSVAL(estimateModel))
62     {
63         CV_ERROR (CV_StsBadArg, "Pointer point to not CvCrossValidationModel");
64     }
65
66     result = ((CvCrossValidationModel*)estimateModel)->sampleIdxTrain;
67
68         __END__
69
70     return result;
71 } // End of cvCrossValGetTrainIdxMatrix
72
73 /****************************************************************************************/
74 // Return pointer to checkIdx. Function DOES NOT FILL this matrix!
75 ML_IMPL
76 const CvMat* cvCrossValGetCheckIdxMatrix (const CvStatModel* estimateModel)
77 {
78     CvMat* result = NULL;
79
80         CV_FUNCNAME ("cvCrossValGetCheckIdxMatrix");
81         __BEGIN__
82
83     if (!CV_IS_CROSSVAL (estimateModel))
84     {
85         CV_ERROR (CV_StsBadArg, "Pointer point to not CvCrossValidationModel");
86     }
87
88     result = ((CvCrossValidationModel*)estimateModel)->sampleIdxEval;
89
90         __END__
91
92     return result;
93 } // End of cvCrossValGetCheckIdxMatrix
94
95 /****************************************************************************************/
96 // Create new Idx-matrix for next classifiers training and return code of result.
97 //   Result is 0 if function can't make next step (error input or folds are finished),
98 //   it is 1 if all was correct, and it is 2 if current fold wasn't' checked.
99 ML_IMPL
100 int cvCrossValNextStep (CvStatModel* estimateModel)
101 {
102     int result = 0;
103
104         CV_FUNCNAME ("cvCrossValGetNextTrainIdx");
105         __BEGIN__
106
107     CvCrossValidationModel* crVal = (CvCrossValidationModel*) estimateModel;
108     int k, fold;
109
110     if (!CV_IS_CROSSVAL (estimateModel))
111     {
112         CV_ERROR (CV_StsBadArg, "Pointer point to not CvCrossValidationModel");
113     }
114
115     fold = ++crVal->current_fold;
116
117     if (fold >= crVal->folds_all)
118     {
119         if (fold == crVal->folds_all)
120             EXIT;
121         else
122         {
123             CV_ERROR (CV_StsInternal, "All iterations has end long ago");
124         }
125     }
126
127     k = crVal->folds[fold + 1] - crVal->folds[fold];
128     crVal->sampleIdxTrain->data.i = crVal->sampleIdxAll + crVal->folds[fold + 1];
129     crVal->sampleIdxTrain->cols = crVal->samples_all - k;
130     crVal->sampleIdxEval->data.i = crVal->sampleIdxAll + crVal->folds[fold];
131     crVal->sampleIdxEval->cols = k;
132
133     if (crVal->is_checked)
134     {
135         crVal->is_checked = 0;
136         result = 1;
137     }
138     else
139     {
140         result = 2;
141     }
142
143         __END__
144
145     return result;
146 }
147
148 /****************************************************************************************/
149 // Do checking part of loop  of cross-validations metod.
150 ML_IMPL
151 void cvCrossValCheckClassifier (CvStatModel*  estimateModel,
152                           const CvStatModel*  model, 
153                           const CvMat*        trainData, 
154                                 int           sample_t_flag,
155                           const CvMat*        trainClasses)
156 {
157         CV_FUNCNAME ("cvCrossValCheckClassifier ");
158         __BEGIN__
159
160     CvCrossValidationModel* crVal = (CvCrossValidationModel*) estimateModel;
161     int  i, j, k;
162     int* data;
163     float* responses_fl;
164     int    step;
165     float* responses_result;
166     int* responses_i;
167     double te, te1;
168     double sum_c, sum_p, sum_pp, sum_cp, sum_cc, sq_err;
169
170 // Check input data to correct values.
171     if (!CV_IS_CROSSVAL (estimateModel))
172     {
173         CV_ERROR (CV_StsBadArg,"First parameter point to not CvCrossValidationModel");
174     }
175     if (!CV_IS_STAT_MODEL (model))
176     {
177         CV_ERROR (CV_StsBadArg, "Second parameter point to not CvStatModel");
178     }
179     if (!CV_IS_MAT (trainData))
180     {
181         CV_ERROR (CV_StsBadArg, "Third parameter point to not CvMat");
182     }
183     if (!CV_IS_MAT (trainClasses))
184     {
185         CV_ERROR (CV_StsBadArg, "Fifth parameter point to not CvMat");
186     }
187     if (crVal->is_checked)
188     {
189         CV_ERROR (CV_StsInternal, "This iterations already was checked");
190     }
191
192 // Initialize.
193     k = crVal->sampleIdxEval->cols;
194     data = crVal->sampleIdxEval->data.i;
195
196 // Eval tested feature vectors.
197     CV_CALL (cvStatModelMultiPredict (model, trainData, sample_t_flag, 
198                                          crVal->predict_results, NULL, crVal->sampleIdxEval));
199 // Count number if correct results.
200     responses_result = crVal->predict_results->data.fl;
201     if (crVal->is_regression)
202     {
203         sum_c = sum_p = sum_pp = sum_cp = sum_cc = sq_err = 0;
204         if (CV_MAT_TYPE (trainClasses->type) == CV_32FC1)
205         {
206             responses_fl = trainClasses->data.fl;
207             step = trainClasses->rows == 1 ? 1 : trainClasses->step / sizeof(float);
208             for (i = 0; i < k; i++)
209             {
210                 te = responses_result[*data];
211                 te1 = responses_fl[*data * step];
212                 sum_c += te1;
213                 sum_p += te;
214                 sum_cc += te1 * te1;
215                 sum_pp += te * te;
216                 sum_cp += te1 * te;
217                 te -= te1;
218                 sq_err += te  * te;
219
220                 data++;
221             }
222         }
223         else
224         {
225             responses_i = trainClasses->data.i;
226             step = trainClasses->rows == 1 ? 1 : trainClasses->step / sizeof(int);
227             for (i = 0; i < k; i++)
228             {
229                 te = responses_result[*data];
230                 te1 = responses_i[*data * step];
231                 sum_c += te1;
232                 sum_p += te;
233                 sum_cc += te1 * te1;
234                 sum_pp += te * te;
235                 sum_cp += te1 * te;
236                 te -= te1;
237                 sq_err += te  * te;
238
239                 data++;
240             }
241         }
242     // Fixing new internal values of accuracy.
243         crVal->sum_correct += sum_c;
244         crVal->sum_predict += sum_p;
245         crVal->sum_cc += sum_cc;
246         crVal->sum_pp += sum_pp;
247         crVal->sum_cp += sum_cp;
248         crVal->sq_error += sq_err;
249     }
250     else
251     {
252         if (CV_MAT_TYPE (trainClasses->type) == CV_32FC1)
253         {
254             responses_fl = trainClasses->data.fl;
255             step = trainClasses->rows == 1 ? 1 : trainClasses->step / sizeof(float);
256             for (i = 0, j = 0; i < k; i++)
257             {
258                 if (cvRound (responses_result[*data]) == cvRound (responses_fl[*data * step]))
259                     j++;
260                 data++;
261             }
262         }
263         else
264         {
265             responses_i = trainClasses->data.i;
266             step = trainClasses->rows == 1 ? 1 : trainClasses->step / sizeof(int);
267             for (i = 0, j = 0; i < k; i++)
268             {
269                 if (cvRound (responses_result[*data]) == responses_i[*data * step])
270                     j++;
271                 data++;
272             }
273         }
274     // Fixing new internal values of accuracy.
275         crVal->correct_results += j;
276     }
277 // Fixing that this fold already checked.
278     crVal->all_results += k;
279     crVal->is_checked = 1;
280
281         __END__
282 } // End of cvCrossValCheckClassifier
283
284 /****************************************************************************************/
285 // Return current accuracy.
286 ML_IMPL
287 float cvCrossValGetResult (const CvStatModel* estimateModel,
288                                  float*       correlation)
289 {
290     float result = 0;
291
292         CV_FUNCNAME ("cvCrossValGetResult");
293         __BEGIN__
294
295     double te, te1;
296     CvCrossValidationModel* crVal = (CvCrossValidationModel*)estimateModel;
297
298     if (!CV_IS_CROSSVAL (estimateModel))
299     {
300         CV_ERROR (CV_StsBadArg, "Pointer point to not CvCrossValidationModel");
301     }
302
303     if (crVal->all_results)
304     {
305         if (crVal->is_regression)
306         {
307             result = ((float)crVal->sq_error) / crVal->all_results;
308             if (correlation)
309             {
310                 te = crVal->all_results * crVal->sum_cp - 
311                                              crVal->sum_correct * crVal->sum_predict;
312                 te *= te;
313                 te1 = (crVal->all_results * crVal->sum_cc - 
314                                     crVal->sum_correct * crVal->sum_correct) *
315                            (crVal->all_results * crVal->sum_pp - 
316                                     crVal->sum_predict * crVal->sum_predict);
317                 *correlation = (float)(te / te1);
318
319             }
320         }
321         else
322         {
323             result = ((float)crVal->correct_results) / crVal->all_results;
324         }
325     }
326
327         __END__
328
329     return result;
330 }
331
332 /****************************************************************************************/
333 // Reset cross-validation EstimateModel to state the same as it was immidiatly after 
334 //   its creating.
335 ML_IMPL
336 void cvCrossValReset (CvStatModel* estimateModel)
337 {
338         CV_FUNCNAME ("cvCrossValReset");
339         __BEGIN__
340
341     CvCrossValidationModel* crVal = (CvCrossValidationModel*)estimateModel;
342
343     if (!CV_IS_CROSSVAL (estimateModel))
344     {
345         CV_ERROR (CV_StsBadArg, "Pointer point to not CvCrossValidationModel");
346     }
347
348     crVal->current_fold = -1;
349     crVal->is_checked = 1;
350     crVal->all_results = 0;
351     crVal->correct_results = 0;
352     crVal->sq_error = 0;
353     crVal->sum_correct = 0;
354     crVal->sum_predict = 0;
355     crVal->sum_cc = 0;
356     crVal->sum_pp = 0;
357     crVal->sum_cp = 0;
358
359         __END__
360 }
361
362 /****************************************************************************************/
363 // This function is standart CvStatModel field to release cross-validation EstimateModel.
364 ML_IMPL
365 void cvReleaseCrossValidationModel (CvStatModel** model)
366 {
367     CvCrossValidationModel* pModel;
368
369         CV_FUNCNAME ("cvReleaseCrossValidationModel");
370         __BEGIN__
371     
372     if (!model)
373     {
374         CV_ERROR (CV_StsNullPtr, "");
375     }
376
377     pModel = (CvCrossValidationModel*)*model;
378     if (!pModel)
379     {
380         return;
381     }
382     if (!CV_IS_CROSSVAL (pModel))
383     {
384         CV_ERROR (CV_StsBadArg, "");
385     }
386
387     cvFree (&pModel->sampleIdxAll);
388     cvFree (&pModel->folds);
389     cvReleaseMat (&pModel->sampleIdxEval);
390     cvReleaseMat (&pModel->sampleIdxTrain);
391     cvReleaseMat (&pModel->predict_results);
392
393     cvFree (model);
394
395         __END__
396 } // End of cvReleaseCrossValidationModel.
397
398 /****************************************************************************************/
399 // This function create cross-validation EstimateModel.
400 ML_IMPL CvStatModel* 
401 cvCreateCrossValidationEstimateModel(
402              int                samples_all,
403        const CvStatModelParams* estimateParams,
404        const CvMat*             sampleIdx)
405 {
406     CvStatModel*            model   = NULL;
407     CvCrossValidationModel* crVal   = NULL;
408
409         CV_FUNCNAME ("cvCreateCrossValidationEstimateModel");
410         __BEGIN__
411
412     int  k_fold = 10;
413
414     int  i, j, k, s_len;
415     int  samples_selected;
416     CvRNG rng; 
417     CvRNG* prng;
418     int* res_s_data;
419     int* te_s_data;
420     int* folds;
421
422     rng = cvRNG(cvGetTickCount());
423     cvRandInt (&rng); cvRandInt (&rng); cvRandInt (&rng); cvRandInt (&rng);
424 // Check input parameters.
425     if (estimateParams)
426         k_fold = ((CvCrossValidationParams*)estimateParams)->k_fold;
427     if (!k_fold)
428     {
429         CV_ERROR (CV_StsBadArg, "Error in parameters of cross-validation (k_fold == 0)!");
430     }
431     if (samples_all <= 0)
432     {
433         CV_ERROR (CV_StsBadArg, "<samples_all> should be positive!");
434     }
435
436 // Alloc memory and fill standart StatModel's fields.
437     CV_CALL (crVal = (CvCrossValidationModel*)cvCreateStatModel (
438                             CV_STAT_MODEL_MAGIC_VAL | CV_CROSSVAL_MAGIC_VAL, 
439                             sizeof(CvCrossValidationModel),
440                             cvReleaseCrossValidationModel,
441                             NULL, NULL));
442     crVal->current_fold    = -1;
443     crVal->folds_all       = k_fold;
444     if (estimateParams && ((CvCrossValidationParams*)estimateParams)->is_regression)
445         crVal->is_regression = 1;
446     else 
447         crVal->is_regression = 0;
448     if (estimateParams && ((CvCrossValidationParams*)estimateParams)->rng)
449         prng = ((CvCrossValidationParams*)estimateParams)->rng;
450     else
451         prng = &rng;
452
453     // Check and preprocess sample indices.
454     if (sampleIdx)
455     {
456         int s_step;
457         int s_type = 0;
458         
459         if (!CV_IS_MAT (sampleIdx))
460             CV_ERROR (CV_StsBadArg, "Invalid sampleIdx array");
461
462         if (sampleIdx->rows != 1 && sampleIdx->cols != 1)
463             CV_ERROR (CV_StsBadSize, "sampleIdx array must be 1-dimensional");
464
465         s_len = sampleIdx->rows + sampleIdx->cols - 1;
466         s_step = sampleIdx->rows == 1 ? 
467                                      1 : sampleIdx->step / CV_ELEM_SIZE(sampleIdx->type);
468
469         s_type = CV_MAT_TYPE (sampleIdx->type);
470
471         switch (s_type)
472         {
473         case CV_8UC1:
474         case CV_8SC1:
475             {
476             uchar* s_data = sampleIdx->data.ptr;
477                 
478             // sampleIdx is array of 1's and 0's -
479             // i.e. it is a mask of the selected samples
480             if( s_len != samples_all )
481                 CV_ERROR (CV_StsUnmatchedSizes,
482        "Sample mask should contain as many elements as the total number of samples");
483             
484             samples_selected = 0;
485             for (i = 0; i < s_len; i++)
486                 samples_selected += s_data[i * s_step] != 0;
487
488             if (samples_selected == 0)
489                 CV_ERROR (CV_StsOutOfRange, "No samples is selected!");
490             }
491             s_len = samples_selected;
492             break;
493         case CV_32SC1:
494             if (s_len > samples_all)
495                 CV_ERROR (CV_StsOutOfRange,
496         "sampleIdx array may not contain more elements than the total number of samples");
497             samples_selected = s_len;
498             break;
499         default:
500             CV_ERROR (CV_StsUnsupportedFormat, "Unsupported sampleIdx array data type "
501                                                "(it should be 8uC1, 8sC1 or 32sC1)");
502         }
503
504         // Alloc additional memory for internal Idx and fill it.
505 /*!!*/  CV_CALL (res_s_data = crVal->sampleIdxAll = 
506                                                  (int*)cvAlloc (2 * s_len * sizeof(int)));
507
508         if (s_type < CV_32SC1)
509         {
510             uchar* s_data = sampleIdx->data.ptr;
511             for (i = 0; i < s_len; i++)
512                 if (s_data[i * s_step])
513                 {
514                     *res_s_data++ = i;
515                 }
516             res_s_data = crVal->sampleIdxAll;
517         }
518         else
519         {
520             int* s_data = sampleIdx->data.i;
521             int out_of_order = 0;
522
523             for (i = 0; i < s_len; i++)
524             {
525                 res_s_data[i] = s_data[i * s_step];
526                 if (i > 0 && res_s_data[i] < res_s_data[i - 1])
527                     out_of_order = 1;
528             }
529
530             if (out_of_order)
531                 qsort (res_s_data, s_len, sizeof(res_s_data[0]), icvCmpIntegers);
532             
533             if (res_s_data[0] < 0 ||
534                 res_s_data[s_len - 1] >= samples_all)
535                     CV_ERROR (CV_StsBadArg, "There are out-of-range sample indices");
536             for (i = 1; i < s_len; i++)
537                 if (res_s_data[i] <= res_s_data[i - 1])
538                     CV_ERROR (CV_StsBadArg, "There are duplicated");
539         }
540     }
541     else // if (sampleIdx)
542     {
543         // Alloc additional memory for internal Idx and fill it.
544         s_len = samples_all;
545         CV_CALL (res_s_data = crVal->sampleIdxAll = (int*)cvAlloc (2 * s_len * sizeof(int)));
546         for (i = 0; i < s_len; i++)
547         {
548             *res_s_data++ = i;
549         }
550         res_s_data = crVal->sampleIdxAll;
551     } // if (sampleIdx) ... else 
552
553 // Resort internal Idx.
554     te_s_data = res_s_data + s_len;
555     for (i = s_len; i > 1; i--)
556     {
557         j = cvRandInt (prng) % i;
558         k = *(--te_s_data);
559         *te_s_data = res_s_data[j];
560         res_s_data[j] = k;
561     }
562
563 // Duplicate resorted internal Idx. 
564 // It will be used to simplify operation of getting trainIdx.
565     te_s_data = res_s_data + s_len;
566     for (i = 0; i < s_len; i++)
567     {
568         *te_s_data++ = *res_s_data++;
569     }
570
571 // Cut sampleIdxAll to parts.
572     if (k_fold > 0)
573     {
574         if (k_fold > s_len)
575         {
576             CV_ERROR (CV_StsBadArg, 
577                         "Error in parameters of cross-validation ('k_fold' > #samples)!");
578         }
579         folds = crVal->folds = (int*) cvAlloc ((k_fold + 1) * sizeof (int));
580         *folds++ = 0;
581         for (i = 1; i < k_fold; i++)
582         {
583             *folds++ = cvRound (i * s_len * 1. / k_fold);
584         }
585         *folds = s_len;
586         folds = crVal->folds;
587
588         crVal->max_fold_size = (s_len - 1) / k_fold + 1;
589     }
590     else
591     {
592         k = -k_fold;
593         crVal->max_fold_size = k;
594         if (k >= s_len)
595         {
596             CV_ERROR (CV_StsBadArg, 
597                       "Error in parameters of cross-validation (-'k_fold' > #samples)!");
598         }
599         crVal->folds_all = k = (s_len - 1) / k + 1;
600
601         folds = crVal->folds = (int*) cvAlloc ((k + 1) * sizeof (int));
602         for (i = 0; i < k; i++)
603         {
604             *folds++ = -i * k_fold;
605         }
606         *folds = s_len;
607         folds = crVal->folds;
608     }
609
610 // Prepare other internal fields to working.
611     CV_CALL (crVal->predict_results = cvCreateMat (1, samples_all, CV_32FC1));
612     CV_CALL (crVal->sampleIdxEval = cvCreateMatHeader (1, 1, CV_32SC1));
613     CV_CALL (crVal->sampleIdxTrain = cvCreateMatHeader (1, 1, CV_32SC1));
614     crVal->sampleIdxEval->cols = 0;
615     crVal->sampleIdxTrain->cols = 0;
616     crVal->samples_all = s_len;
617     crVal->is_checked = 1;
618
619     crVal->getTrainIdxMat = cvCrossValGetTrainIdxMatrix;
620     crVal->getCheckIdxMat = cvCrossValGetCheckIdxMatrix;
621     crVal->nextStep = cvCrossValNextStep;
622     crVal->check = cvCrossValCheckClassifier;
623     crVal->getResult = cvCrossValGetResult;
624     crVal->reset = cvCrossValReset;
625
626     model = (CvStatModel*)crVal;
627
628         __END__
629
630     if (!model)
631     {
632         cvReleaseCrossValidationModel ((CvStatModel**)&crVal);
633     }
634
635     return model;
636 } // End of cvCreateCrossValidationEstimateModel
637             
638
639 /****************************************************************************************\
640 *                Extended interface with backcalls for models                            *
641 \****************************************************************************************/
642 ML_IMPL float
643 cvCrossValidation (const CvMat*            trueData,
644                          int               tflag,
645                    const CvMat*            trueClasses,
646                          CvStatModel*     (*createClassifier) (const CvMat*, 
647                                                                      int, 
648                                                                const CvMat*,
649                                                                const CvClassifierTrainParams*,
650                                                                const CvMat*, 
651                                                                const CvMat*, 
652                                                                const CvMat*, 
653                                                                const CvMat*),
654                    const CvClassifierTrainParams*    estimateParams,
655                    const CvClassifierTrainParams*    trainParams,
656                    const CvMat*            compIdx,
657                    const CvMat*            sampleIdx,
658                          CvStatModel**     pCrValModel,
659                    const CvMat*            typeMask,
660                    const CvMat*            missedMeasurementMask)
661 {
662     CvCrossValidationModel* crVal = NULL;
663     float  result = 0;
664     CvStatModel* pClassifier = NULL;
665
666         CV_FUNCNAME ("cvCrossValidation");
667         __BEGIN__
668
669     const CvMat* trainDataIdx;
670     int    samples_all;
671
672 // checking input data
673     if ((createClassifier) == NULL)
674     {
675         CV_ERROR (CV_StsNullPtr, "Null pointer to functiion which create classifier");
676     }
677     if (pCrValModel && *pCrValModel && !CV_IS_CROSSVAL(*pCrValModel))
678     {
679         CV_ERROR (CV_StsBadArg, 
680            "<pCrValModel> point to not cross-validation model");
681     }
682
683 // initialization
684     if (pCrValModel && *pCrValModel)
685     {
686         crVal = (CvCrossValidationModel*)*pCrValModel;
687         crVal->reset ((CvStatModel*)crVal);
688     }
689     else
690     {
691         samples_all = ((tflag) ? trueData->rows : trueData->cols);
692         CV_CALL (crVal = (CvCrossValidationModel*)
693            cvCreateCrossValidationEstimateModel (samples_all, estimateParams, sampleIdx));
694     }
695
696     CV_CALL (trainDataIdx = crVal->getTrainIdxMat ((CvStatModel*)crVal));
697
698 // operation loop
699     for (; crVal->nextStep((CvStatModel*)crVal) != 0; )
700     {
701         CV_CALL (pClassifier = createClassifier (trueData, tflag, trueClasses, 
702                     trainParams, compIdx, trainDataIdx, typeMask, missedMeasurementMask));
703         CV_CALL (crVal->check ((CvStatModel*)crVal, pClassifier, 
704                                                            trueData, tflag, trueClasses));
705
706         pClassifier->release (&pClassifier);
707     }
708
709 // Get result and fill output field.
710     CV_CALL (result = crVal->getResult ((CvStatModel*)crVal, 0));
711
712     if (pCrValModel && !*pCrValModel)
713         *pCrValModel = (CvStatModel*)crVal;
714
715         __END__
716
717 // Free all memory that should be freed.
718     if (pClassifier)
719         pClassifier->release (&pClassifier);
720     if (crVal && (!pCrValModel || !*pCrValModel))
721         crVal->release ((CvStatModel**)&crVal);
722
723     return result;
724 } // End of cvCrossValidation
725
726 #endif
727
728 /* End of file */